aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/layerscape/patches-4.14/820-sec-support-layerscape.patch
diff options
context:
space:
mode:
authorBiwen Li <biwen.li@nxp.com>2018-11-02 11:21:57 +0800
committerHauke Mehrtens <hauke@hauke-m.de>2018-12-18 20:17:23 +0100
commit0a827ebd2fa3c7dc210aff0a30d0dc1d536ed89c (patch)
treeb80223fffb0814b6db33f48dd3aaa047cd3e0299 /target/linux/layerscape/patches-4.14/820-sec-support-layerscape.patch
parent7bd6969acce763a7117b33a6647b8c5dbbf2b0aa (diff)
downloadupstream-0a827ebd2fa3c7dc210aff0a30d0dc1d536ed89c.tar.gz
upstream-0a827ebd2fa3c7dc210aff0a30d0dc1d536ed89c.tar.bz2
upstream-0a827ebd2fa3c7dc210aff0a30d0dc1d536ed89c.zip
layerscape: upgrade kernel to 4.14
This patch is to upgrade kernel to 4.14 for layerscape. patches-4.14 for layerscape included two categories. - NXP Layerscape SDK kernel-4.14 patches All patches on tag LSDK-18.09-V4.14 were ported to OpenWrt kernel. Since there were hundreds patches, we had to make an all-in-one patch for each IP/feature. See below links for LSDK kernel. https://lsdk.github.io/components.html https://source.codeaurora.org/external/qoriq/qoriq-components/linux - Non-LSDK kernel patches Other patches which were not in LSDK were just put in patches-4.14. Kept below patches from patches-4.9. 303-dts-layerscape-add-traverse-ls1043.patch 821-add-esdhc-vsel-to-ls1043.patch 822-rgmii-fixed-link.patch Renamed and rebase them as below in patches-4.14, 303-add-DTS-for-Traverse-LS1043-Boards.patch 712-sdk-dpaa-rgmii-fixed-link.patch 824-mmc-sdhci-of-esdhc-add-voltage-switch-support-for-ls.patch Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> Signed-off-by: Biwen Li <biwen.li@nxp.com>
Diffstat (limited to 'target/linux/layerscape/patches-4.14/820-sec-support-layerscape.patch')
-rw-r--r--target/linux/layerscape/patches-4.14/820-sec-support-layerscape.patch13093
1 files changed, 13093 insertions, 0 deletions
diff --git a/target/linux/layerscape/patches-4.14/820-sec-support-layerscape.patch b/target/linux/layerscape/patches-4.14/820-sec-support-layerscape.patch
new file mode 100644
index 0000000000..9cec9dc70a
--- /dev/null
+++ b/target/linux/layerscape/patches-4.14/820-sec-support-layerscape.patch
@@ -0,0 +1,13093 @@
+From 936d5f485f2ff837cdd7d49839771bd3367e8b92 Mon Sep 17 00:00:00 2001
+From: Biwen Li <biwen.li@nxp.com>
+Date: Tue, 30 Oct 2018 18:28:03 +0800
+Subject: [PATCH 37/40] sec: support layerscape
+This is an integrated patch of sec for layerscape
+
+Signed-off-by: Alex Porosanu <alexandru.porosanu@nxp.com>
+Signed-off-by: Cristian Stoica <cristian.stoica@nxp.com>
+Signed-off-by: Guanhua Gao <guanhua.gao@nxp.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+Signed-off-by: Horia Geantă horia.geanta@nxp.com
+Signed-off-by: Radu Alexe <radu.alexe@nxp.com>
+Signed-off-by: Tudor Ambarus <tudor-dan.ambarus@nxp.com>
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com>
+Signed-off-by: Biwen Li <biwen.li@nxp.com>
+---
+ crypto/Kconfig | 20 +
+ crypto/Makefile | 1 +
+ crypto/tcrypt.c | 27 +-
+ crypto/testmgr.c | 244 ++
+ crypto/testmgr.h | 219 ++
+ crypto/tls.c | 607 +++
+ drivers/crypto/Makefile | 2 +-
+ drivers/crypto/caam/Kconfig | 57 +-
+ drivers/crypto/caam/Makefile | 10 +-
+ drivers/crypto/caam/caamalg.c | 131 +-
+ drivers/crypto/caam/caamalg_desc.c | 761 +++-
+ drivers/crypto/caam/caamalg_desc.h | 47 +-
+ drivers/crypto/caam/caamalg_qi.c | 927 ++++-
+ drivers/crypto/caam/caamalg_qi2.c | 5691 +++++++++++++++++++++++++++
+ drivers/crypto/caam/caamalg_qi2.h | 274 ++
+ drivers/crypto/caam/caamhash.c | 132 +-
+ drivers/crypto/caam/caamhash_desc.c | 108 +
+ drivers/crypto/caam/caamhash_desc.h | 49 +
+ drivers/crypto/caam/compat.h | 2 +
+ drivers/crypto/caam/ctrl.c | 23 +-
+ drivers/crypto/caam/desc.h | 62 +-
+ drivers/crypto/caam/desc_constr.h | 52 +-
+ drivers/crypto/caam/dpseci.c | 865 ++++
+ drivers/crypto/caam/dpseci.h | 433 ++
+ drivers/crypto/caam/dpseci_cmd.h | 287 ++
+ drivers/crypto/caam/error.c | 75 +-
+ drivers/crypto/caam/error.h | 6 +-
+ drivers/crypto/caam/intern.h | 1 +
+ drivers/crypto/caam/jr.c | 42 +
+ drivers/crypto/caam/jr.h | 2 +
+ drivers/crypto/caam/key_gen.c | 30 -
+ drivers/crypto/caam/key_gen.h | 30 +
+ drivers/crypto/caam/qi.c | 85 +-
+ drivers/crypto/caam/qi.h | 2 +-
+ drivers/crypto/caam/regs.h | 2 +
+ drivers/crypto/caam/sg_sw_qm.h | 46 +-
+ drivers/crypto/talitos.c | 8 +
+ 37 files changed, 11006 insertions(+), 354 deletions(-)
+ create mode 100644 crypto/tls.c
+ create mode 100644 drivers/crypto/caam/caamalg_qi2.c
+ create mode 100644 drivers/crypto/caam/caamalg_qi2.h
+ create mode 100644 drivers/crypto/caam/caamhash_desc.c
+ create mode 100644 drivers/crypto/caam/caamhash_desc.h
+ create mode 100644 drivers/crypto/caam/dpseci.c
+ create mode 100644 drivers/crypto/caam/dpseci.h
+ create mode 100644 drivers/crypto/caam/dpseci_cmd.h
+
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -312,6 +312,26 @@ config CRYPTO_ECHAINIV
+ a sequence number xored with a salt. This is the default
+ algorithm for CBC.
+
++config CRYPTO_TLS
++ tristate "TLS support"
++ select CRYPTO_AEAD
++ select CRYPTO_BLKCIPHER
++ select CRYPTO_MANAGER
++ select CRYPTO_HASH
++ select CRYPTO_NULL
++ select CRYPTO_AUTHENC
++ help
++ Support for TLS 1.0 record encryption and decryption
++
++ This module adds support for encryption/decryption of TLS 1.0 frames
++ using blockcipher algorithms. The name of the resulting algorithm is
++ "tls10(hmac(<digest>),cbc(<cipher>))". By default, the generic base
++ algorithms are used (e.g. aes-generic, sha1-generic), but hardware
++ accelerated versions will be used automatically if available.
++
++ User-space applications (OpenSSL, GnuTLS) can offload TLS 1.0
++ operations through AF_ALG or cryptodev interfaces
++
+ comment "Block modes"
+
+ config CRYPTO_CBC
+--- a/crypto/Makefile
++++ b/crypto/Makefile
+@@ -118,6 +118,7 @@ obj-$(CONFIG_CRYPTO_CRC32C) += crc32c_ge
+ obj-$(CONFIG_CRYPTO_CRC32) += crc32_generic.o
+ obj-$(CONFIG_CRYPTO_CRCT10DIF) += crct10dif_common.o crct10dif_generic.o
+ obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o authencesn.o
++obj-$(CONFIG_CRYPTO_TLS) += tls.o
+ obj-$(CONFIG_CRYPTO_LZO) += lzo.o
+ obj-$(CONFIG_CRYPTO_LZ4) += lz4.o
+ obj-$(CONFIG_CRYPTO_LZ4HC) += lz4hc.o
+--- a/crypto/tcrypt.c
++++ b/crypto/tcrypt.c
+@@ -76,7 +76,7 @@ static char *check[] = {
+ "khazad", "wp512", "wp384", "wp256", "tnepres", "xeta", "fcrypt",
+ "camellia", "seed", "salsa20", "rmd128", "rmd160", "rmd256", "rmd320",
+ "lzo", "cts", "zlib", "sha3-224", "sha3-256", "sha3-384", "sha3-512",
+- NULL
++ "rsa", NULL
+ };
+
+ struct tcrypt_result {
+@@ -355,11 +355,13 @@ static void test_aead_speed(const char *
+ iv);
+ aead_request_set_ad(req, aad_size);
+
+- if (secs)
++ if (secs) {
+ ret = test_aead_jiffies(req, enc, *b_size,
+ secs);
+- else
++ cond_resched();
++ } else {
+ ret = test_aead_cycles(req, enc, *b_size);
++ }
+
+ if (ret) {
+ pr_err("%s() failed return code=%d\n", e, ret);
+@@ -736,12 +738,14 @@ static void test_ahash_speed_common(cons
+
+ ahash_request_set_crypt(req, sg, output, speed[i].plen);
+
+- if (secs)
++ if (secs) {
+ ret = test_ahash_jiffies(req, speed[i].blen,
+ speed[i].plen, output, secs);
+- else
++ cond_resched();
++ } else {
+ ret = test_ahash_cycles(req, speed[i].blen,
+ speed[i].plen, output);
++ }
+
+ if (ret) {
+ pr_err("hashing failed ret=%d\n", ret);
+@@ -959,12 +963,14 @@ static void test_skcipher_speed(const ch
+
+ skcipher_request_set_crypt(req, sg, sg, *b_size, iv);
+
+- if (secs)
++ if (secs) {
+ ret = test_acipher_jiffies(req, enc,
+ *b_size, secs);
+- else
++ cond_resched();
++ } else {
+ ret = test_acipher_cycles(req, enc,
+ *b_size);
++ }
+
+ if (ret) {
+ pr_err("%s() failed flags=%x\n", e,
+@@ -1336,6 +1342,10 @@ static int do_test(const char *alg, u32
+ ret += tcrypt_test("hmac(sha3-512)");
+ break;
+
++ case 115:
++ ret += tcrypt_test("rsa");
++ break;
++
+ case 150:
+ ret += tcrypt_test("ansi_cprng");
+ break;
+@@ -1397,6 +1407,9 @@ static int do_test(const char *alg, u32
+ case 190:
+ ret += tcrypt_test("authenc(hmac(sha512),cbc(des3_ede))");
+ break;
++ case 191:
++ ret += tcrypt_test("tls10(hmac(sha1),cbc(aes))");
++ break;
+ case 200:
+ test_cipher_speed("ecb(aes)", ENCRYPT, sec, NULL, 0,
+ speed_template_16_24_32);
+--- a/crypto/testmgr.c
++++ b/crypto/testmgr.c
+@@ -117,6 +117,13 @@ struct drbg_test_suite {
+ unsigned int count;
+ };
+
++struct tls_test_suite {
++ struct {
++ struct tls_testvec *vecs;
++ unsigned int count;
++ } enc, dec;
++};
++
+ struct akcipher_test_suite {
+ const struct akcipher_testvec *vecs;
+ unsigned int count;
+@@ -140,6 +147,7 @@ struct alg_test_desc {
+ struct hash_test_suite hash;
+ struct cprng_test_suite cprng;
+ struct drbg_test_suite drbg;
++ struct tls_test_suite tls;
+ struct akcipher_test_suite akcipher;
+ struct kpp_test_suite kpp;
+ } suite;
+@@ -991,6 +999,233 @@ static int test_aead(struct crypto_aead
+ return 0;
+ }
+
++static int __test_tls(struct crypto_aead *tfm, int enc,
++ struct tls_testvec *template, unsigned int tcount,
++ const bool diff_dst)
++{
++ const char *algo = crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm));
++ unsigned int i, k, authsize;
++ char *q;
++ struct aead_request *req;
++ struct scatterlist *sg;
++ struct scatterlist *sgout;
++ const char *e, *d;
++ struct tcrypt_result result;
++ void *input;
++ void *output;
++ void *assoc;
++ char *iv;
++ char *key;
++ char *xbuf[XBUFSIZE];
++ char *xoutbuf[XBUFSIZE];
++ char *axbuf[XBUFSIZE];
++ int ret = -ENOMEM;
++
++ if (testmgr_alloc_buf(xbuf))
++ goto out_noxbuf;
++
++ if (diff_dst && testmgr_alloc_buf(xoutbuf))
++ goto out_nooutbuf;
++
++ if (testmgr_alloc_buf(axbuf))
++ goto out_noaxbuf;
++
++ iv = kzalloc(MAX_IVLEN, GFP_KERNEL);
++ if (!iv)
++ goto out_noiv;
++
++ key = kzalloc(MAX_KEYLEN, GFP_KERNEL);
++ if (!key)
++ goto out_nokey;
++
++ sg = kmalloc(sizeof(*sg) * 8 * (diff_dst ? 2 : 1), GFP_KERNEL);
++ if (!sg)
++ goto out_nosg;
++
++ sgout = sg + 8;
++
++ d = diff_dst ? "-ddst" : "";
++ e = enc ? "encryption" : "decryption";
++
++ init_completion(&result.completion);
++
++ req = aead_request_alloc(tfm, GFP_KERNEL);
++ if (!req) {
++ pr_err("alg: tls%s: Failed to allocate request for %s\n",
++ d, algo);
++ goto out;
++ }
++
++ aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
++ tcrypt_complete, &result);
++
++ for (i = 0; i < tcount; i++) {
++ input = xbuf[0];
++ assoc = axbuf[0];
++
++ ret = -EINVAL;
++ if (WARN_ON(template[i].ilen > PAGE_SIZE ||
++ template[i].alen > PAGE_SIZE))
++ goto out;
++
++ memcpy(assoc, template[i].assoc, template[i].alen);
++ memcpy(input, template[i].input, template[i].ilen);
++
++ if (template[i].iv)
++ memcpy(iv, template[i].iv, MAX_IVLEN);
++ else
++ memset(iv, 0, MAX_IVLEN);
++
++ crypto_aead_clear_flags(tfm, ~0);
++
++ if (template[i].klen > MAX_KEYLEN) {
++ pr_err("alg: aead%s: setkey failed on test %d for %s: key size %d > %d\n",
++ d, i, algo, template[i].klen, MAX_KEYLEN);
++ ret = -EINVAL;
++ goto out;
++ }
++ memcpy(key, template[i].key, template[i].klen);
++
++ ret = crypto_aead_setkey(tfm, key, template[i].klen);
++ if (!ret == template[i].fail) {
++ pr_err("alg: tls%s: setkey failed on test %d for %s: flags=%x\n",
++ d, i, algo, crypto_aead_get_flags(tfm));
++ goto out;
++ } else if (ret)
++ continue;
++
++ authsize = 20;
++ ret = crypto_aead_setauthsize(tfm, authsize);
++ if (ret) {
++ pr_err("alg: aead%s: Failed to set authsize to %u on test %d for %s\n",
++ d, authsize, i, algo);
++ goto out;
++ }
++
++ k = !!template[i].alen;
++ sg_init_table(sg, k + 1);
++ sg_set_buf(&sg[0], assoc, template[i].alen);
++ sg_set_buf(&sg[k], input, (enc ? template[i].rlen :
++ template[i].ilen));
++ output = input;
++
++ if (diff_dst) {
++ sg_init_table(sgout, k + 1);
++ sg_set_buf(&sgout[0], assoc, template[i].alen);
++
++ output = xoutbuf[0];
++ sg_set_buf(&sgout[k], output,
++ (enc ? template[i].rlen : template[i].ilen));
++ }
++
++ aead_request_set_crypt(req, sg, (diff_dst) ? sgout : sg,
++ template[i].ilen, iv);
++
++ aead_request_set_ad(req, template[i].alen);
++
++ ret = enc ? crypto_aead_encrypt(req) : crypto_aead_decrypt(req);
++
++ switch (ret) {
++ case 0:
++ if (template[i].novrfy) {
++ /* verification was supposed to fail */
++ pr_err("alg: tls%s: %s failed on test %d for %s: ret was 0, expected -EBADMSG\n",
++ d, e, i, algo);
++ /* so really, we got a bad message */
++ ret = -EBADMSG;
++ goto out;
++ }
++ break;
++ case -EINPROGRESS:
++ case -EBUSY:
++ wait_for_completion(&result.completion);
++ reinit_completion(&result.completion);
++ ret = result.err;
++ if (!ret)
++ break;
++ case -EBADMSG:
++ /* verification failure was expected */
++ if (template[i].novrfy)
++ continue;
++ /* fall through */
++ default:
++ pr_err("alg: tls%s: %s failed on test %d for %s: ret=%d\n",
++ d, e, i, algo, -ret);
++ goto out;
++ }
++
++ q = output;
++ if (memcmp(q, template[i].result, template[i].rlen)) {
++ pr_err("alg: tls%s: Test %d failed on %s for %s\n",
++ d, i, e, algo);
++ hexdump(q, template[i].rlen);
++ pr_err("should be:\n");
++ hexdump(template[i].result, template[i].rlen);
++ ret = -EINVAL;
++ goto out;
++ }
++ }
++
++out:
++ aead_request_free(req);
++
++ kfree(sg);
++out_nosg:
++ kfree(key);
++out_nokey:
++ kfree(iv);
++out_noiv:
++ testmgr_free_buf(axbuf);
++out_noaxbuf:
++ if (diff_dst)
++ testmgr_free_buf(xoutbuf);
++out_nooutbuf:
++ testmgr_free_buf(xbuf);
++out_noxbuf:
++ return ret;
++}
++
++static int test_tls(struct crypto_aead *tfm, int enc,
++ struct tls_testvec *template, unsigned int tcount)
++{
++ int ret;
++ /* test 'dst == src' case */
++ ret = __test_tls(tfm, enc, template, tcount, false);
++ if (ret)
++ return ret;
++ /* test 'dst != src' case */
++ return __test_tls(tfm, enc, template, tcount, true);
++}
++
++static int alg_test_tls(const struct alg_test_desc *desc, const char *driver,
++ u32 type, u32 mask)
++{
++ struct crypto_aead *tfm;
++ int err = 0;
++
++ tfm = crypto_alloc_aead(driver, type, mask);
++ if (IS_ERR(tfm)) {
++ pr_err("alg: aead: Failed to load transform for %s: %ld\n",
++ driver, PTR_ERR(tfm));
++ return PTR_ERR(tfm);
++ }
++
++ if (desc->suite.tls.enc.vecs) {
++ err = test_tls(tfm, ENCRYPT, desc->suite.tls.enc.vecs,
++ desc->suite.tls.enc.count);
++ if (err)
++ goto out;
++ }
++
++ if (!err && desc->suite.tls.dec.vecs)
++ err = test_tls(tfm, DECRYPT, desc->suite.tls.dec.vecs,
++ desc->suite.tls.dec.count);
++
++out:
++ crypto_free_aead(tfm);
++ return err;
++}
++
+ static int test_cipher(struct crypto_cipher *tfm, int enc,
+ const struct cipher_testvec *template,
+ unsigned int tcount)
+@@ -3518,6 +3753,15 @@ static const struct alg_test_desc alg_te
+ .hash = __VECS(tgr192_tv_template)
+ }
+ }, {
++ .alg = "tls10(hmac(sha1),cbc(aes))",
++ .test = alg_test_tls,
++ .suite = {
++ .tls = {
++ .enc = __VECS(tls_enc_tv_template),
++ .dec = __VECS(tls_dec_tv_template)
++ }
++ }
++ }, {
+ .alg = "vmac(aes)",
+ .test = alg_test_hash,
+ .suite = {
+--- a/crypto/testmgr.h
++++ b/crypto/testmgr.h
+@@ -125,6 +125,20 @@ struct drbg_testvec {
+ size_t expectedlen;
+ };
+
++struct tls_testvec {
++ char *key; /* wrapped keys for encryption and authentication */
++ char *iv; /* initialization vector */
++ char *input; /* input data */
++ char *assoc; /* associated data: seq num, type, version, input len */
++ char *result; /* result data */
++ unsigned char fail; /* the test failure is expected */
++ unsigned char novrfy; /* dec verification failure expected */
++ unsigned char klen; /* key length */
++ unsigned short ilen; /* input data length */
++ unsigned short alen; /* associated data length */
++ unsigned short rlen; /* result length */
++};
++
+ struct akcipher_testvec {
+ const unsigned char *key;
+ const unsigned char *m;
+@@ -153,6 +167,211 @@ struct kpp_testvec {
+ static const char zeroed_string[48];
+
+ /*
++ * TLS1.0 synthetic test vectors
++ */
++static struct tls_testvec tls_enc_tv_template[] = {
++ {
++#ifdef __LITTLE_ENDIAN
++ .key = "\x08\x00" /* rta length */
++ "\x01\x00" /* rta type */
++#else
++ .key = "\x00\x08" /* rta length */
++ "\x00\x01" /* rta type */
++#endif
++ "\x00\x00\x00\x10" /* enc key length */
++ "authenticationkey20benckeyis16_bytes",
++ .klen = 8 + 20 + 16,
++ .iv = "iv0123456789abcd",
++ .input = "Single block msg",
++ .ilen = 16,
++ .assoc = "\x00\x01\x02\x03\x04\x05\x06\x07"
++ "\x00\x03\x01\x00\x10",
++ .alen = 13,
++ .result = "\xd5\xac\xb\xd2\xac\xad\x3f\xb1"
++ "\x59\x79\x1e\x91\x5f\x52\x14\x9c"
++ "\xc0\x75\xd8\x4c\x97\x0f\x07\x73"
++ "\xdc\x89\x47\x49\x49\xcb\x30\x6b"
++ "\x1b\x45\x23\xa1\xd0\x51\xcf\x02"
++ "\x2e\xa8\x5d\xa0\xfe\xca\x82\x61",
++ .rlen = 16 + 20 + 12,
++ }, {
++#ifdef __LITTLE_ENDIAN
++ .key = "\x08\x00" /* rta length */
++ "\x01\x00" /* rta type */
++#else
++ .key = "\x00\x08" /* rta length */
++ "\x00\x01" /* rta type */
++#endif
++ "\x00\x00\x00\x10" /* enc key length */
++ "authenticationkey20benckeyis16_bytes",
++ .klen = 8 + 20 + 16,
++ .iv = "iv0123456789abcd",
++ .input = "",
++ .ilen = 0,
++ .assoc = "\x00\x01\x02\x03\x04\x05\x06\x07"
++ "\x00\x03\x01\x00\x00",
++ .alen = 13,
++ .result = "\x58\x2a\x11\xc\x86\x8e\x4b\x67"
++ "\x2d\x16\x26\x1a\xac\x4b\xe2\x1a"
++ "\xe9\x6a\xcc\x4d\x6f\x79\x8a\x45"
++ "\x1f\x4e\x27\xf2\xa7\x59\xb4\x5a",
++ .rlen = 20 + 12,
++ }, {
++#ifdef __LITTLE_ENDIAN
++ .key = "\x08\x00" /* rta length */
++ "\x01\x00" /* rta type */
++#else
++ .key = "\x00\x08" /* rta length */
++ "\x00\x01" /* rta type */
++#endif
++ "\x00\x00\x00\x10" /* enc key length */
++ "authenticationkey20benckeyis16_bytes",
++ .klen = 8 + 20 + 16,
++ .iv = "iv0123456789abcd",
++ .input = "285 bytes plaintext285 bytes plaintext285 bytes"
++ " plaintext285 bytes plaintext285 bytes plaintext285"
++ " bytes plaintext285 bytes plaintext285 bytes"
++ " plaintext285 bytes plaintext285 bytes plaintext285"
++ " bytes plaintext285 bytes plaintext285 bytes"
++ " plaintext285 bytes plaintext285 bytes plaintext285"
++ " bytes plaintext285 bytes plaintext",
++ .ilen = 285,
++ .assoc = "\x00\x01\x02\x03\x04\x05\x06\x07"
++ "\x00\x03\x01\x01\x1d",
++ .alen = 13,
++ .result = "\x80\x23\x82\x44\x14\x2a\x1d\x94\xc\xc2\x1d\xd"
++ "\x3a\x32\x89\x4c\x57\x30\xa8\x89\x76\x46\xcc\x90"
++ "\x1d\x88\xb8\xa6\x1a\x58\xe\x2d\xeb\x2c\xc7\x3a"
++ "\x52\x4e\xdb\xb3\x1e\x83\x11\xf5\x3c\xce\x6e\x94"
++ "\xd3\x26\x6a\x9a\xd\xbd\xc7\x98\xb9\xb3\x3a\x51"
++ "\x1e\x4\x84\x8a\x8f\x54\x9a\x51\x69\x9c\xce\x31"
++ "\x8d\x5d\x8b\xee\x5f\x70\xc\xc9\xb8\x50\x54\xf8"
++ "\xb2\x4a\x7a\xcd\xeb\x7a\x82\x81\xc6\x41\xc8\x50"
++ "\x91\x8d\xc8\xed\xcd\x40\x8f\x55\xd1\xec\xc9\xac"
++ "\x15\x18\xf9\x20\xa0\xed\x18\xa1\xe3\x56\xe3\x14"
++ "\xe5\xe8\x66\x63\x20\xed\xe4\x62\x9d\xa3\xa4\x1d"
++ "\x81\x89\x18\xf2\x36\xae\xc8\x8a\x2b\xbc\xc3\xb8"
++ "\x80\xf\x97\x21\x36\x39\x8\x84\x23\x18\x9e\x9c"
++ "\x72\x32\x75\x2d\x2e\xf9\x60\xb\xe8\xcc\xd9\x74"
++ "\x4\x1b\x8e\x99\xc1\x94\xee\xd0\xac\x4e\xfc\x7e"
++ "\xf1\x96\xb3\xe7\x14\xb8\xf2\xc\x25\x97\x82\x6b"
++ "\xbd\x0\x65\xab\x5c\xe3\x16\xfb\x68\xef\xea\x9d"
++ "\xff\x44\x1d\x2a\x44\xf5\xc8\x56\x77\xb7\xbf\x13"
++ "\xc8\x54\xdb\x92\xfe\x16\x4c\xbe\x18\xe9\xb\x8d"
++ "\xb\xd4\x43\x58\x43\xaa\xf4\x3\x80\x97\x62\xd5"
++ "\xdf\x3c\x28\xaa\xee\x48\x4b\x55\x41\x1b\x31\x2"
++ "\xbe\xa0\x1c\xbd\xb7\x22\x2a\xe5\x53\x72\x73\x20"
++ "\x44\x4f\xe6\x1\x2b\x34\x33\x11\x7d\xfb\x10\xc1"
++ "\x66\x7c\xa6\xf4\x48\x36\x5e\x2\xda\x41\x4b\x3e"
++ "\xe7\x80\x17\x17\xce\xf1\x3e\x6a\x8e\x26\xf3\xb7"
++ "\x2b\x85\xd\x31\x8d\xba\x6c\x22\xb4\x28\x55\x7e"
++ "\x2a\x9e\x26\xf1\x3d\x21\xac\x65",
++ .rlen = 285 + 20 + 15,
++ }
++};
++
++static struct tls_testvec tls_dec_tv_template[] = {
++ {
++#ifdef __LITTLE_ENDIAN
++ .key = "\x08\x00" /* rta length */
++ "\x01\x00" /* rta type */
++#else
++ .key = "\x00\x08" /* rta length */
++ "\x00\x01" /* rta type */
++#endif
++ "\x00\x00\x00\x10" /* enc key length */
++ "authenticationkey20benckeyis16_bytes",
++ .klen = 8 + 20 + 16,
++ .iv = "iv0123456789abcd",
++ .input = "\xd5\xac\xb\xd2\xac\xad\x3f\xb1"
++ "\x59\x79\x1e\x91\x5f\x52\x14\x9c"
++ "\xc0\x75\xd8\x4c\x97\x0f\x07\x73"
++ "\xdc\x89\x47\x49\x49\xcb\x30\x6b"
++ "\x1b\x45\x23\xa1\xd0\x51\xcf\x02"
++ "\x2e\xa8\x5d\xa0\xfe\xca\x82\x61",
++ .ilen = 16 + 20 + 12,
++ .assoc = "\x00\x01\x02\x03\x04\x05\x06\x07"
++ "\x00\x03\x01\x00\x30",
++ .alen = 13,
++ .result = "Single block msg",
++ .rlen = 16,
++ }, {
++#ifdef __LITTLE_ENDIAN
++ .key = "\x08\x00" /* rta length */
++ "\x01\x00" /* rta type */
++#else
++ .key = "\x00\x08" /* rta length */
++ "\x00\x01" /* rta type */
++#endif
++ "\x00\x00\x00\x10" /* enc key length */
++ "authenticationkey20benckeyis16_bytes",
++ .klen = 8 + 20 + 16,
++ .iv = "iv0123456789abcd",
++ .input = "\x58\x2a\x11\xc\x86\x8e\x4b\x67"
++ "\x2d\x16\x26\x1a\xac\x4b\xe2\x1a"
++ "\xe9\x6a\xcc\x4d\x6f\x79\x8a\x45"
++ "\x1f\x4e\x27\xf2\xa7\x59\xb4\x5a",
++ .ilen = 20 + 12,
++ .assoc = "\x00\x01\x02\x03\x04\x05\x06\x07"
++ "\x00\x03\x01\x00\x20",
++ .alen = 13,
++ .result = "",
++ .rlen = 0,
++ }, {
++#ifdef __LITTLE_ENDIAN
++ .key = "\x08\x00" /* rta length */
++ "\x01\x00" /* rta type */
++#else
++ .key = "\x00\x08" /* rta length */
++ "\x00\x01" /* rta type */
++#endif
++ "\x00\x00\x00\x10" /* enc key length */
++ "authenticationkey20benckeyis16_bytes",
++ .klen = 8 + 20 + 16,
++ .iv = "iv0123456789abcd",
++ .input = "\x80\x23\x82\x44\x14\x2a\x1d\x94\xc\xc2\x1d\xd"
++ "\x3a\x32\x89\x4c\x57\x30\xa8\x89\x76\x46\xcc\x90"
++ "\x1d\x88\xb8\xa6\x1a\x58\xe\x2d\xeb\x2c\xc7\x3a"
++ "\x52\x4e\xdb\xb3\x1e\x83\x11\xf5\x3c\xce\x6e\x94"
++ "\xd3\x26\x6a\x9a\xd\xbd\xc7\x98\xb9\xb3\x3a\x51"
++ "\x1e\x4\x84\x8a\x8f\x54\x9a\x51\x69\x9c\xce\x31"
++ "\x8d\x5d\x8b\xee\x5f\x70\xc\xc9\xb8\x50\x54\xf8"
++ "\xb2\x4a\x7a\xcd\xeb\x7a\x82\x81\xc6\x41\xc8\x50"
++ "\x91\x8d\xc8\xed\xcd\x40\x8f\x55\xd1\xec\xc9\xac"
++ "\x15\x18\xf9\x20\xa0\xed\x18\xa1\xe3\x56\xe3\x14"
++ "\xe5\xe8\x66\x63\x20\xed\xe4\x62\x9d\xa3\xa4\x1d"
++ "\x81\x89\x18\xf2\x36\xae\xc8\x8a\x2b\xbc\xc3\xb8"
++ "\x80\xf\x97\x21\x36\x39\x8\x84\x23\x18\x9e\x9c"
++ "\x72\x32\x75\x2d\x2e\xf9\x60\xb\xe8\xcc\xd9\x74"
++ "\x4\x1b\x8e\x99\xc1\x94\xee\xd0\xac\x4e\xfc\x7e"
++ "\xf1\x96\xb3\xe7\x14\xb8\xf2\xc\x25\x97\x82\x6b"
++ "\xbd\x0\x65\xab\x5c\xe3\x16\xfb\x68\xef\xea\x9d"
++ "\xff\x44\x1d\x2a\x44\xf5\xc8\x56\x77\xb7\xbf\x13"
++ "\xc8\x54\xdb\x92\xfe\x16\x4c\xbe\x18\xe9\xb\x8d"
++ "\xb\xd4\x43\x58\x43\xaa\xf4\x3\x80\x97\x62\xd5"
++ "\xdf\x3c\x28\xaa\xee\x48\x4b\x55\x41\x1b\x31\x2"
++ "\xbe\xa0\x1c\xbd\xb7\x22\x2a\xe5\x53\x72\x73\x20"
++ "\x44\x4f\xe6\x1\x2b\x34\x33\x11\x7d\xfb\x10\xc1"
++ "\x66\x7c\xa6\xf4\x48\x36\x5e\x2\xda\x41\x4b\x3e"
++ "\xe7\x80\x17\x17\xce\xf1\x3e\x6a\x8e\x26\xf3\xb7"
++ "\x2b\x85\xd\x31\x8d\xba\x6c\x22\xb4\x28\x55\x7e"
++ "\x2a\x9e\x26\xf1\x3d\x21\xac\x65",
++
++ .ilen = 285 + 20 + 15,
++ .assoc = "\x00\x01\x02\x03\x04\x05\x06\x07"
++ "\x00\x03\x01\x01\x40",
++ .alen = 13,
++ .result = "285 bytes plaintext285 bytes plaintext285 bytes"
++ " plaintext285 bytes plaintext285 bytes plaintext285"
++ " bytes plaintext285 bytes plaintext285 bytes"
++ " plaintext285 bytes plaintext285 bytes plaintext285"
++ " bytes plaintext285 bytes plaintext285 bytes"
++ " plaintext285 bytes plaintext285 bytes plaintext",
++ .rlen = 285,
++ }
++};
++
++/*
+ * RSA test vectors. Borrowed from openSSL.
+ */
+ static const struct akcipher_testvec rsa_tv_template[] = {
+--- /dev/null
++++ b/crypto/tls.c
+@@ -0,0 +1,607 @@
++/*
++ * Copyright 2013 Freescale Semiconductor, Inc.
++ * Copyright 2017 NXP Semiconductor, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the Free
++ * Software Foundation; either version 2 of the License, or (at your option)
++ * any later version.
++ *
++ */
++
++#include <crypto/internal/aead.h>
++#include <crypto/internal/hash.h>
++#include <crypto/internal/skcipher.h>
++#include <crypto/authenc.h>
++#include <crypto/null.h>
++#include <crypto/scatterwalk.h>
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/rtnetlink.h>
++
++struct tls_instance_ctx {
++ struct crypto_ahash_spawn auth;
++ struct crypto_skcipher_spawn enc;
++};
++
++struct crypto_tls_ctx {
++ unsigned int reqoff;
++ struct crypto_ahash *auth;
++ struct crypto_skcipher *enc;
++ struct crypto_skcipher *null;
++};
++
++struct tls_request_ctx {
++ /*
++ * cryptlen holds the payload length in the case of encryption or
++ * payload_len + icv_len + padding_len in case of decryption
++ */
++ unsigned int cryptlen;
++ /* working space for partial results */
++ struct scatterlist tmp[2];
++ struct scatterlist cipher[2];
++ struct scatterlist dst[2];
++ char tail[];
++};
++
++struct async_op {
++ struct completion completion;
++ int err;
++};
++
++static void tls_async_op_done(struct crypto_async_request *req, int err)
++{
++ struct async_op *areq = req->data;
++
++ if (err == -EINPROGRESS)
++ return;
++
++ areq->err = err;
++ complete(&areq->completion);
++}
++
++static int crypto_tls_setkey(struct crypto_aead *tls, const u8 *key,
++ unsigned int keylen)
++{
++ struct crypto_tls_ctx *ctx = crypto_aead_ctx(tls);
++ struct crypto_ahash *auth = ctx->auth;
++ struct crypto_skcipher *enc = ctx->enc;
++ struct crypto_authenc_keys keys;
++ int err = -EINVAL;
++
++ if (crypto_authenc_extractkeys(&keys, key, keylen) != 0)
++ goto badkey;
++
++ crypto_ahash_clear_flags(auth, CRYPTO_TFM_REQ_MASK);
++ crypto_ahash_set_flags(auth, crypto_aead_get_flags(tls) &
++ CRYPTO_TFM_REQ_MASK);
++ err = crypto_ahash_setkey(auth, keys.authkey, keys.authkeylen);
++ crypto_aead_set_flags(tls, crypto_ahash_get_flags(auth) &
++ CRYPTO_TFM_RES_MASK);
++
++ if (err)
++ goto out;
++
++ crypto_skcipher_clear_flags(enc, CRYPTO_TFM_REQ_MASK);
++ crypto_skcipher_set_flags(enc, crypto_aead_get_flags(tls) &
++ CRYPTO_TFM_REQ_MASK);
++ err = crypto_skcipher_setkey(enc, keys.enckey, keys.enckeylen);
++ crypto_aead_set_flags(tls, crypto_skcipher_get_flags(enc) &
++ CRYPTO_TFM_RES_MASK);
++
++out:
++ return err;
++
++badkey:
++ crypto_aead_set_flags(tls, CRYPTO_TFM_RES_BAD_KEY_LEN);
++ goto out;
++}
++
++/**
++ * crypto_tls_genicv - Calculate hmac digest for a TLS record
++ * @hash: (output) buffer to save the digest into
++ * @src: (input) scatterlist with the assoc and payload data
++ * @srclen: (input) size of the source buffer (assoclen + cryptlen)
++ * @req: (input) aead request
++ **/
++static int crypto_tls_genicv(u8 *hash, struct scatterlist *src,
++ unsigned int srclen, struct aead_request *req)
++{
++ struct crypto_aead *tls = crypto_aead_reqtfm(req);
++ struct crypto_tls_ctx *ctx = crypto_aead_ctx(tls);
++ struct tls_request_ctx *treq_ctx = aead_request_ctx(req);
++ struct async_op ahash_op;
++ struct ahash_request *ahreq = (void *)(treq_ctx->tail + ctx->reqoff);
++ unsigned int flags = CRYPTO_TFM_REQ_MAY_SLEEP;
++ int err = -EBADMSG;
++
++ /* Bail out if the request assoc len is 0 */
++ if (!req->assoclen)
++ return err;
++
++ init_completion(&ahash_op.completion);
++
++ /* the hash transform to be executed comes from the original request */
++ ahash_request_set_tfm(ahreq, ctx->auth);
++ /* prepare the hash request with input data and result pointer */
++ ahash_request_set_crypt(ahreq, src, hash, srclen);
++ /* set the notifier for when the async hash function returns */
++ ahash_request_set_callback(ahreq, aead_request_flags(req) & flags,
++ tls_async_op_done, &ahash_op);
++
++ /* Calculate the digest on the given data. The result is put in hash */
++ err = crypto_ahash_digest(ahreq);
++ if (err == -EINPROGRESS) {
++ err = wait_for_completion_interruptible(&ahash_op.completion);
++ if (!err)
++ err = ahash_op.err;
++ }
++
++ return err;
++}
++
++/**
++ * crypto_tls_gen_padicv - Calculate and pad hmac digest for a TLS record
++ * @hash: (output) buffer to save the digest and padding into
++ * @phashlen: (output) the size of digest + padding
++ * @req: (input) aead request
++ **/
++static int crypto_tls_gen_padicv(u8 *hash, unsigned int *phashlen,
++ struct aead_request *req)
++{
++ struct crypto_aead *tls = crypto_aead_reqtfm(req);
++ unsigned int hash_size = crypto_aead_authsize(tls);
++ unsigned int block_size = crypto_aead_blocksize(tls);
++ unsigned int srclen = req->cryptlen + hash_size;
++ unsigned int icvlen = req->cryptlen + req->assoclen;
++ unsigned int padlen;
++ int err;
++
++ err = crypto_tls_genicv(hash, req->src, icvlen, req);
++ if (err)
++ goto out;
++
++ /* add padding after digest */
++ padlen = block_size - (srclen % block_size);
++ memset(hash + hash_size, padlen - 1, padlen);
++
++ *phashlen = hash_size + padlen;
++out:
++ return err;
++}
++
++static int crypto_tls_copy_data(struct aead_request *req,
++ struct scatterlist *src,
++ struct scatterlist *dst,
++ unsigned int len)
++{
++ struct crypto_aead *tls = crypto_aead_reqtfm(req);
++ struct crypto_tls_ctx *ctx = crypto_aead_ctx(tls);
++ SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null);
++
++ skcipher_request_set_tfm(skreq, ctx->null);
++ skcipher_request_set_callback(skreq, aead_request_flags(req),
++ NULL, NULL);
++ skcipher_request_set_crypt(skreq, src, dst, len, NULL);
++
++ return crypto_skcipher_encrypt(skreq);
++}
++
++static int crypto_tls_encrypt(struct aead_request *req)
++{
++ struct crypto_aead *tls = crypto_aead_reqtfm(req);
++ struct crypto_tls_ctx *ctx = crypto_aead_ctx(tls);
++ struct tls_request_ctx *treq_ctx = aead_request_ctx(req);
++ struct skcipher_request *skreq;
++ struct scatterlist *cipher = treq_ctx->cipher;
++ struct scatterlist *tmp = treq_ctx->tmp;
++ struct scatterlist *sg, *src, *dst;
++ unsigned int cryptlen, phashlen;
++ u8 *hash = treq_ctx->tail;
++ int err;
++
++ /*
++ * The hash result is saved at the beginning of the tls request ctx
++ * and is aligned as required by the hash transform. Enough space was
++ * allocated in crypto_tls_init_tfm to accommodate the difference. The
++ * requests themselves start later at treq_ctx->tail + ctx->reqoff so
++ * the result is not overwritten by the second (cipher) request.
++ */
++ hash = (u8 *)ALIGN((unsigned long)hash +
++ crypto_ahash_alignmask(ctx->auth),
++ crypto_ahash_alignmask(ctx->auth) + 1);
++
++ /*
++ * STEP 1: create ICV together with necessary padding
++ */
++ err = crypto_tls_gen_padicv(hash, &phashlen, req);
++ if (err)
++ return err;
++
++ /*
++ * STEP 2: Hash and padding are combined with the payload
++ * depending on the form it arrives. Scatter tables must have at least
++ * one page of data before chaining with another table and can't have
++ * an empty data page. The following code addresses these requirements.
++ *
++ * If the payload is empty, only the hash is encrypted, otherwise the
++ * payload scatterlist is merged with the hash. A special merging case
++ * is when the payload has only one page of data. In that case the
++ * payload page is moved to another scatterlist and prepared there for
++ * encryption.
++ */
++ if (req->cryptlen) {
++ src = scatterwalk_ffwd(tmp, req->src, req->assoclen);
++
++ sg_init_table(cipher, 2);
++ sg_set_buf(cipher + 1, hash, phashlen);
++
++ if (sg_is_last(src)) {
++ sg_set_page(cipher, sg_page(src), req->cryptlen,
++ src->offset);
++ src = cipher;
++ } else {
++ unsigned int rem_len = req->cryptlen;
++
++ for (sg = src; rem_len > sg->length; sg = sg_next(sg))
++ rem_len -= min(rem_len, sg->length);
++
++ sg_set_page(cipher, sg_page(sg), rem_len, sg->offset);
++ sg_chain(sg, 1, cipher);
++ }
++ } else {
++ sg_init_one(cipher, hash, phashlen);
++ src = cipher;
++ }
++
++ /**
++ * If src != dst copy the associated data from source to destination.
++ * In both cases fast-forward passed the associated data in the dest.
++ */
++ if (req->src != req->dst) {
++ err = crypto_tls_copy_data(req, req->src, req->dst,
++ req->assoclen);
++ if (err)
++ return err;
++ }
++ dst = scatterwalk_ffwd(treq_ctx->dst, req->dst, req->assoclen);
++
++ /*
++ * STEP 3: encrypt the frame and return the result
++ */
++ cryptlen = req->cryptlen + phashlen;
++
++ /*
++ * The hash and the cipher are applied at different times and their
++ * requests can use the same memory space without interference
++ */
++ skreq = (void *)(treq_ctx->tail + ctx->reqoff);
++ skcipher_request_set_tfm(skreq, ctx->enc);
++ skcipher_request_set_crypt(skreq, src, dst, cryptlen, req->iv);
++ skcipher_request_set_callback(skreq, aead_request_flags(req),
++ req->base.complete, req->base.data);
++ /*
++ * Apply the cipher transform. The result will be in req->dst when the
++ * asynchronuous call terminates
++ */
++ err = crypto_skcipher_encrypt(skreq);
++
++ return err;
++}
++
++static int crypto_tls_decrypt(struct aead_request *req)
++{
++ struct crypto_aead *tls = crypto_aead_reqtfm(req);
++ struct crypto_tls_ctx *ctx = crypto_aead_ctx(tls);
++ struct tls_request_ctx *treq_ctx = aead_request_ctx(req);
++ unsigned int cryptlen = req->cryptlen;
++ unsigned int hash_size = crypto_aead_authsize(tls);
++ unsigned int block_size = crypto_aead_blocksize(tls);
++ struct skcipher_request *skreq = (void *)(treq_ctx->tail + ctx->reqoff);
++ struct scatterlist *tmp = treq_ctx->tmp;
++ struct scatterlist *src, *dst;
++
++ u8 padding[255]; /* padding can be 0-255 bytes */
++ u8 pad_size;
++ u16 *len_field;
++ u8 *ihash, *hash = treq_ctx->tail;
++
++ int paderr = 0;
++ int err = -EINVAL;
++ int i;
++ struct async_op ciph_op;
++
++ /*
++ * Rule out bad packets. The input packet length must be at least one
++ * byte more than the hash_size
++ */
++ if (cryptlen <= hash_size || cryptlen % block_size)
++ goto out;
++
++ /*
++ * Step 1 - Decrypt the source. Fast-forward past the associated data
++ * to the encrypted data. The result will be overwritten in place so
++ * that the decrypted data will be adjacent to the associated data. The
++ * last step (computing the hash) will have it's input data already
++ * prepared and ready to be accessed at req->src.
++ */
++ src = scatterwalk_ffwd(tmp, req->src, req->assoclen);
++ dst = src;
++
++ init_completion(&ciph_op.completion);
++ skcipher_request_set_tfm(skreq, ctx->enc);
++ skcipher_request_set_callback(skreq, aead_request_flags(req),
++ tls_async_op_done, &ciph_op);
++ skcipher_request_set_crypt(skreq, src, dst, cryptlen, req->iv);
++ err = crypto_skcipher_decrypt(skreq);
++ if (err == -EINPROGRESS) {
++ err = wait_for_completion_interruptible(&ciph_op.completion);
++ if (!err)
++ err = ciph_op.err;
++ }
++ if (err)
++ goto out;
++
++ /*
++ * Step 2 - Verify padding
++ * Retrieve the last byte of the payload; this is the padding size.
++ */
++ cryptlen -= 1;
++ scatterwalk_map_and_copy(&pad_size, dst, cryptlen, 1, 0);
++
++ /* RFC recommendation for invalid padding size. */
++ if (cryptlen < pad_size + hash_size) {
++ pad_size = 0;
++ paderr = -EBADMSG;
++ }
++ cryptlen -= pad_size;
++ scatterwalk_map_and_copy(padding, dst, cryptlen, pad_size, 0);
++
++ /* Padding content must be equal with pad_size. We verify it all */
++ for (i = 0; i < pad_size; i++)
++ if (padding[i] != pad_size)
++ paderr = -EBADMSG;
++
++ /*
++ * Step 3 - Verify hash
++ * Align the digest result as required by the hash transform. Enough
++ * space was allocated in crypto_tls_init_tfm
++ */
++ hash = (u8 *)ALIGN((unsigned long)hash +
++ crypto_ahash_alignmask(ctx->auth),
++ crypto_ahash_alignmask(ctx->auth) + 1);
++ /*
++ * Two bytes at the end of the associated data make the length field.
++ * It must be updated with the length of the cleartext message before
++ * the hash is calculated.
++ */
++ len_field = sg_virt(req->src) + req->assoclen - 2;
++ cryptlen -= hash_size;
++ *len_field = htons(cryptlen);
++
++ /* This is the hash from the decrypted packet. Save it for later */
++ ihash = hash + hash_size;
++ scatterwalk_map_and_copy(ihash, dst, cryptlen, hash_size, 0);
++
++ /* Now compute and compare our ICV with the one from the packet */
++ err = crypto_tls_genicv(hash, req->src, cryptlen + req->assoclen, req);
++ if (!err)
++ err = memcmp(hash, ihash, hash_size) ? -EBADMSG : 0;
++
++ if (req->src != req->dst) {
++ err = crypto_tls_copy_data(req, req->src, req->dst, cryptlen +
++ req->assoclen);
++ if (err)
++ goto out;
++ }
++
++ /* return the first found error */
++ if (paderr)
++ err = paderr;
++
++out:
++ aead_request_complete(req, err);
++ return err;
++}
++
++static int crypto_tls_init_tfm(struct crypto_aead *tfm)
++{
++ struct aead_instance *inst = aead_alg_instance(tfm);
++ struct tls_instance_ctx *ictx = aead_instance_ctx(inst);
++ struct crypto_tls_ctx *ctx = crypto_aead_ctx(tfm);
++ struct crypto_ahash *auth;
++ struct crypto_skcipher *enc;
++ struct crypto_skcipher *null;
++ int err;
++
++ auth = crypto_spawn_ahash(&ictx->auth);
++ if (IS_ERR(auth))
++ return PTR_ERR(auth);
++
++ enc = crypto_spawn_skcipher(&ictx->enc);
++ err = PTR_ERR(enc);
++ if (IS_ERR(enc))
++ goto err_free_ahash;
++
++ null = crypto_get_default_null_skcipher2();
++ err = PTR_ERR(null);
++ if (IS_ERR(null))
++ goto err_free_skcipher;
++
++ ctx->auth = auth;
++ ctx->enc = enc;
++ ctx->null = null;
++
++ /*
++ * Allow enough space for two digests. The two digests will be compared
++ * during the decryption phase. One will come from the decrypted packet
++ * and the other will be calculated. For encryption, one digest is
++ * padded (up to a cipher blocksize) and chained with the payload
++ */
++ ctx->reqoff = ALIGN(crypto_ahash_digestsize(auth) +
++ crypto_ahash_alignmask(auth),
++ crypto_ahash_alignmask(auth) + 1) +
++ max(crypto_ahash_digestsize(auth),
++ crypto_skcipher_blocksize(enc));
++
++ crypto_aead_set_reqsize(tfm,
++ sizeof(struct tls_request_ctx) +
++ ctx->reqoff +
++ max_t(unsigned int,
++ crypto_ahash_reqsize(auth) +
++ sizeof(struct ahash_request),
++ crypto_skcipher_reqsize(enc) +
++ sizeof(struct skcipher_request)));
++
++ return 0;
++
++err_free_skcipher:
++ crypto_free_skcipher(enc);
++err_free_ahash:
++ crypto_free_ahash(auth);
++ return err;
++}
++
++static void crypto_tls_exit_tfm(struct crypto_aead *tfm)
++{
++ struct crypto_tls_ctx *ctx = crypto_aead_ctx(tfm);
++
++ crypto_free_ahash(ctx->auth);
++ crypto_free_skcipher(ctx->enc);
++ crypto_put_default_null_skcipher2();
++}
++
++static void crypto_tls_free(struct aead_instance *inst)
++{
++ struct tls_instance_ctx *ctx = aead_instance_ctx(inst);
++
++ crypto_drop_skcipher(&ctx->enc);
++ crypto_drop_ahash(&ctx->auth);
++ kfree(inst);
++}
++
++static int crypto_tls_create(struct crypto_template *tmpl, struct rtattr **tb)
++{
++ struct crypto_attr_type *algt;
++ struct aead_instance *inst;
++ struct hash_alg_common *auth;
++ struct crypto_alg *auth_base;
++ struct skcipher_alg *enc;
++ struct tls_instance_ctx *ctx;
++ const char *enc_name;
++ int err;
++
++ algt = crypto_get_attr_type(tb);
++ if (IS_ERR(algt))
++ return PTR_ERR(algt);
++
++ if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
++ return -EINVAL;
++
++ auth = ahash_attr_alg(tb[1], CRYPTO_ALG_TYPE_HASH,
++ CRYPTO_ALG_TYPE_AHASH_MASK |
++ crypto_requires_sync(algt->type, algt->mask));
++ if (IS_ERR(auth))
++ return PTR_ERR(auth);
++
++ auth_base = &auth->base;
++
++ enc_name = crypto_attr_alg_name(tb[2]);
++ err = PTR_ERR(enc_name);
++ if (IS_ERR(enc_name))
++ goto out_put_auth;
++
++ inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
++ err = -ENOMEM;
++ if (!inst)
++ goto out_put_auth;
++
++ ctx = aead_instance_ctx(inst);
++
++ err = crypto_init_ahash_spawn(&ctx->auth, auth,
++ aead_crypto_instance(inst));
++ if (err)
++ goto err_free_inst;
++
++ crypto_set_skcipher_spawn(&ctx->enc, aead_crypto_instance(inst));
++ err = crypto_grab_skcipher(&ctx->enc, enc_name, 0,
++ crypto_requires_sync(algt->type,
++ algt->mask));
++ if (err)
++ goto err_drop_auth;
++
++ enc = crypto_spawn_skcipher_alg(&ctx->enc);
++
++ err = -ENAMETOOLONG;
++ if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
++ "tls10(%s,%s)", auth_base->cra_name,
++ enc->base.cra_name) >= CRYPTO_MAX_ALG_NAME)
++ goto err_drop_enc;
++
++ if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
++ "tls10(%s,%s)", auth_base->cra_driver_name,
++ enc->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
++ goto err_drop_enc;
++
++ inst->alg.base.cra_flags = (auth_base->cra_flags |
++ enc->base.cra_flags) & CRYPTO_ALG_ASYNC;
++ inst->alg.base.cra_priority = enc->base.cra_priority * 10 +
++ auth_base->cra_priority;
++ inst->alg.base.cra_blocksize = enc->base.cra_blocksize;
++ inst->alg.base.cra_alignmask = auth_base->cra_alignmask |
++ enc->base.cra_alignmask;
++ inst->alg.base.cra_ctxsize = sizeof(struct crypto_tls_ctx);
++
++ inst->alg.ivsize = crypto_skcipher_alg_ivsize(enc);
++ inst->alg.chunksize = crypto_skcipher_alg_chunksize(enc);
++ inst->alg.maxauthsize = auth->digestsize;
++
++ inst->alg.init = crypto_tls_init_tfm;
++ inst->alg.exit = crypto_tls_exit_tfm;
++
++ inst->alg.setkey = crypto_tls_setkey;
++ inst->alg.encrypt = crypto_tls_encrypt;
++ inst->alg.decrypt = crypto_tls_decrypt;
++
++ inst->free = crypto_tls_free;
++
++ err = aead_register_instance(tmpl, inst);
++ if (err)
++ goto err_drop_enc;
++
++out:
++ crypto_mod_put(auth_base);
++ return err;
++
++err_drop_enc:
++ crypto_drop_skcipher(&ctx->enc);
++err_drop_auth:
++ crypto_drop_ahash(&ctx->auth);
++err_free_inst:
++ kfree(inst);
++out_put_auth:
++ goto out;
++}
++
++static struct crypto_template crypto_tls_tmpl = {
++ .name = "tls10",
++ .create = crypto_tls_create,
++ .module = THIS_MODULE,
++};
++
++static int __init crypto_tls_module_init(void)
++{
++ return crypto_register_template(&crypto_tls_tmpl);
++}
++
++static void __exit crypto_tls_module_exit(void)
++{
++ crypto_unregister_template(&crypto_tls_tmpl);
++}
++
++module_init(crypto_tls_module_init);
++module_exit(crypto_tls_module_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("TLS 1.0 record encryption");
+--- a/drivers/crypto/Makefile
++++ b/drivers/crypto/Makefile
+@@ -10,7 +10,7 @@ obj-$(CONFIG_CRYPTO_DEV_CHELSIO) += chel
+ obj-$(CONFIG_CRYPTO_DEV_CPT) += cavium/cpt/
+ obj-$(CONFIG_CRYPTO_DEV_NITROX) += cavium/nitrox/
+ obj-$(CONFIG_CRYPTO_DEV_EXYNOS_RNG) += exynos-rng.o
+-obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam/
++obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_COMMON) += caam/
+ obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o
+ obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o
+ obj-$(CONFIG_CRYPTO_DEV_IMGTEC_HASH) += img-hash.o
+--- a/drivers/crypto/caam/Kconfig
++++ b/drivers/crypto/caam/Kconfig
+@@ -1,7 +1,11 @@
++config CRYPTO_DEV_FSL_CAAM_COMMON
++ tristate
++
+ config CRYPTO_DEV_FSL_CAAM
+- tristate "Freescale CAAM-Multicore driver backend"
++ tristate "Freescale CAAM-Multicore platform driver backend"
+ depends on FSL_SOC || ARCH_MXC || ARCH_LAYERSCAPE
+ select SOC_BUS
++ select CRYPTO_DEV_FSL_CAAM_COMMON
+ help
+ Enables the driver module for Freescale's Cryptographic Accelerator
+ and Assurance Module (CAAM), also known as the SEC version 4 (SEC4).
+@@ -12,9 +16,16 @@ config CRYPTO_DEV_FSL_CAAM
+ To compile this driver as a module, choose M here: the module
+ will be called caam.
+
++if CRYPTO_DEV_FSL_CAAM
++
++config CRYPTO_DEV_FSL_CAAM_DEBUG
++ bool "Enable debug output in CAAM driver"
++ help
++ Selecting this will enable printing of various debug
++ information in the CAAM driver.
++
+ config CRYPTO_DEV_FSL_CAAM_JR
+ tristate "Freescale CAAM Job Ring driver backend"
+- depends on CRYPTO_DEV_FSL_CAAM
+ default y
+ help
+ Enables the driver module for Job Rings which are part of
+@@ -25,9 +36,10 @@ config CRYPTO_DEV_FSL_CAAM_JR
+ To compile this driver as a module, choose M here: the module
+ will be called caam_jr.
+
++if CRYPTO_DEV_FSL_CAAM_JR
++
+ config CRYPTO_DEV_FSL_CAAM_RINGSIZE
+ int "Job Ring size"
+- depends on CRYPTO_DEV_FSL_CAAM_JR
+ range 2 9
+ default "9"
+ help
+@@ -45,7 +57,6 @@ config CRYPTO_DEV_FSL_CAAM_RINGSIZE
+
+ config CRYPTO_DEV_FSL_CAAM_INTC
+ bool "Job Ring interrupt coalescing"
+- depends on CRYPTO_DEV_FSL_CAAM_JR
+ help
+ Enable the Job Ring's interrupt coalescing feature.
+
+@@ -75,7 +86,6 @@ config CRYPTO_DEV_FSL_CAAM_INTC_TIME_THL
+
+ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API
+ tristate "Register algorithm implementations with the Crypto API"
+- depends on CRYPTO_DEV_FSL_CAAM_JR
+ default y
+ select CRYPTO_AEAD
+ select CRYPTO_AUTHENC
+@@ -90,7 +100,7 @@ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API
+
+ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI
+ tristate "Queue Interface as Crypto API backend"
+- depends on CRYPTO_DEV_FSL_CAAM_JR && FSL_DPAA && NET
++ depends on FSL_SDK_DPA && NET
+ default y
+ select CRYPTO_AUTHENC
+ select CRYPTO_BLKCIPHER
+@@ -107,7 +117,6 @@ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI
+
+ config CRYPTO_DEV_FSL_CAAM_AHASH_API
+ tristate "Register hash algorithm implementations with Crypto API"
+- depends on CRYPTO_DEV_FSL_CAAM_JR
+ default y
+ select CRYPTO_HASH
+ help
+@@ -119,7 +128,6 @@ config CRYPTO_DEV_FSL_CAAM_AHASH_API
+
+ config CRYPTO_DEV_FSL_CAAM_PKC_API
+ tristate "Register public key cryptography implementations with Crypto API"
+- depends on CRYPTO_DEV_FSL_CAAM_JR
+ default y
+ select CRYPTO_RSA
+ help
+@@ -131,7 +139,6 @@ config CRYPTO_DEV_FSL_CAAM_PKC_API
+
+ config CRYPTO_DEV_FSL_CAAM_RNG_API
+ tristate "Register caam device for hwrng API"
+- depends on CRYPTO_DEV_FSL_CAAM_JR
+ default y
+ select CRYPTO_RNG
+ select HW_RANDOM
+@@ -142,13 +149,31 @@ config CRYPTO_DEV_FSL_CAAM_RNG_API
+ To compile this as a module, choose M here: the module
+ will be called caamrng.
+
+-config CRYPTO_DEV_FSL_CAAM_DEBUG
+- bool "Enable debug output in CAAM driver"
+- depends on CRYPTO_DEV_FSL_CAAM
+- help
+- Selecting this will enable printing of various debug
+- information in the CAAM driver.
++endif # CRYPTO_DEV_FSL_CAAM_JR
++
++endif # CRYPTO_DEV_FSL_CAAM
++
++config CRYPTO_DEV_FSL_DPAA2_CAAM
++ tristate "QorIQ DPAA2 CAAM (DPSECI) driver"
++ depends on FSL_MC_DPIO
++ select CRYPTO_DEV_FSL_CAAM_COMMON
++ select CRYPTO_BLKCIPHER
++ select CRYPTO_AUTHENC
++ select CRYPTO_AEAD
++ select CRYPTO_HASH
++ ---help---
++ CAAM driver for QorIQ Data Path Acceleration Architecture 2.
++ It handles DPSECI DPAA2 objects that sit on the Management Complex
++ (MC) fsl-mc bus.
++
++ To compile this as a module, choose M here: the module
++ will be called dpaa2_caam.
+
+ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC
+ def_tristate (CRYPTO_DEV_FSL_CAAM_CRYPTO_API || \
+- CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI)
++ CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI || \
++ CRYPTO_DEV_FSL_DPAA2_CAAM)
++
++config CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC
++ def_tristate (CRYPTO_DEV_FSL_CAAM_AHASH_API || \
++ CRYPTO_DEV_FSL_DPAA2_CAAM)
+--- a/drivers/crypto/caam/Makefile
++++ b/drivers/crypto/caam/Makefile
+@@ -6,19 +6,27 @@ ifeq ($(CONFIG_CRYPTO_DEV_FSL_CAAM_DEBUG
+ ccflags-y := -DDEBUG
+ endif
+
++ccflags-y += -DVERSION=\"\"
++
++obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_COMMON) += error.o
+ obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam.o
+ obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_JR) += caam_jr.o
+ obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o
+ obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += caamalg_qi.o
+ obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC) += caamalg_desc.o
+ obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API) += caamhash.o
++obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC) += caamhash_desc.o
+ obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += caamrng.o
+ obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API) += caam_pkc.o
+
+ caam-objs := ctrl.o
+-caam_jr-objs := jr.o key_gen.o error.o
++caam_jr-objs := jr.o key_gen.o
+ caam_pkc-y := caampkc.o pkc_desc.o
+ ifneq ($(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI),)
+ ccflags-y += -DCONFIG_CAAM_QI
+ caam-objs += qi.o
+ endif
++
++obj-$(CONFIG_CRYPTO_DEV_FSL_DPAA2_CAAM) += dpaa2_caam.o
++
++dpaa2_caam-y := caamalg_qi2.o dpseci.o
+--- a/drivers/crypto/caam/caamalg.c
++++ b/drivers/crypto/caam/caamalg.c
+@@ -108,6 +108,7 @@ struct caam_ctx {
+ dma_addr_t sh_desc_dec_dma;
+ dma_addr_t sh_desc_givenc_dma;
+ dma_addr_t key_dma;
++ enum dma_data_direction dir;
+ struct device *jrdev;
+ struct alginfo adata;
+ struct alginfo cdata;
+@@ -118,6 +119,7 @@ static int aead_null_set_sh_desc(struct
+ {
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *jrdev = ctx->jrdev;
++ struct caam_drv_private *ctrlpriv = dev_get_drvdata(jrdev->parent);
+ u32 *desc;
+ int rem_bytes = CAAM_DESC_BYTES_MAX - AEAD_DESC_JOB_IO_LEN -
+ ctx->adata.keylen_pad;
+@@ -136,9 +138,10 @@ static int aead_null_set_sh_desc(struct
+
+ /* aead_encrypt shared descriptor */
+ desc = ctx->sh_desc_enc;
+- cnstr_shdsc_aead_null_encap(desc, &ctx->adata, ctx->authsize);
++ cnstr_shdsc_aead_null_encap(desc, &ctx->adata, ctx->authsize,
++ ctrlpriv->era);
+ dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma,
+- desc_bytes(desc), DMA_TO_DEVICE);
++ desc_bytes(desc), ctx->dir);
+
+ /*
+ * Job Descriptor and Shared Descriptors
+@@ -154,9 +157,10 @@ static int aead_null_set_sh_desc(struct
+
+ /* aead_decrypt shared descriptor */
+ desc = ctx->sh_desc_dec;
+- cnstr_shdsc_aead_null_decap(desc, &ctx->adata, ctx->authsize);
++ cnstr_shdsc_aead_null_decap(desc, &ctx->adata, ctx->authsize,
++ ctrlpriv->era);
+ dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma,
+- desc_bytes(desc), DMA_TO_DEVICE);
++ desc_bytes(desc), ctx->dir);
+
+ return 0;
+ }
+@@ -168,6 +172,7 @@ static int aead_set_sh_desc(struct crypt
+ unsigned int ivsize = crypto_aead_ivsize(aead);
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *jrdev = ctx->jrdev;
++ struct caam_drv_private *ctrlpriv = dev_get_drvdata(jrdev->parent);
+ u32 ctx1_iv_off = 0;
+ u32 *desc, *nonce = NULL;
+ u32 inl_mask;
+@@ -234,9 +239,9 @@ static int aead_set_sh_desc(struct crypt
+ desc = ctx->sh_desc_enc;
+ cnstr_shdsc_aead_encap(desc, &ctx->cdata, &ctx->adata, ivsize,
+ ctx->authsize, is_rfc3686, nonce, ctx1_iv_off,
+- false);
++ false, ctrlpriv->era);
+ dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma,
+- desc_bytes(desc), DMA_TO_DEVICE);
++ desc_bytes(desc), ctx->dir);
+
+ skip_enc:
+ /*
+@@ -266,9 +271,9 @@ skip_enc:
+ desc = ctx->sh_desc_dec;
+ cnstr_shdsc_aead_decap(desc, &ctx->cdata, &ctx->adata, ivsize,
+ ctx->authsize, alg->caam.geniv, is_rfc3686,
+- nonce, ctx1_iv_off, false);
++ nonce, ctx1_iv_off, false, ctrlpriv->era);
+ dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma,
+- desc_bytes(desc), DMA_TO_DEVICE);
++ desc_bytes(desc), ctx->dir);
+
+ if (!alg->caam.geniv)
+ goto skip_givenc;
+@@ -300,9 +305,9 @@ skip_enc:
+ desc = ctx->sh_desc_enc;
+ cnstr_shdsc_aead_givencap(desc, &ctx->cdata, &ctx->adata, ivsize,
+ ctx->authsize, is_rfc3686, nonce,
+- ctx1_iv_off, false);
++ ctx1_iv_off, false, ctrlpriv->era);
+ dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma,
+- desc_bytes(desc), DMA_TO_DEVICE);
++ desc_bytes(desc), ctx->dir);
+
+ skip_givenc:
+ return 0;
+@@ -323,6 +328,7 @@ static int gcm_set_sh_desc(struct crypto
+ {
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *jrdev = ctx->jrdev;
++ unsigned int ivsize = crypto_aead_ivsize(aead);
+ u32 *desc;
+ int rem_bytes = CAAM_DESC_BYTES_MAX - GCM_DESC_JOB_IO_LEN -
+ ctx->cdata.keylen;
+@@ -344,9 +350,9 @@ static int gcm_set_sh_desc(struct crypto
+ }
+
+ desc = ctx->sh_desc_enc;
+- cnstr_shdsc_gcm_encap(desc, &ctx->cdata, ctx->authsize);
++ cnstr_shdsc_gcm_encap(desc, &ctx->cdata, ivsize, ctx->authsize, false);
+ dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma,
+- desc_bytes(desc), DMA_TO_DEVICE);
++ desc_bytes(desc), ctx->dir);
+
+ /*
+ * Job Descriptor and Shared Descriptors
+@@ -361,9 +367,9 @@ static int gcm_set_sh_desc(struct crypto
+ }
+
+ desc = ctx->sh_desc_dec;
+- cnstr_shdsc_gcm_decap(desc, &ctx->cdata, ctx->authsize);
++ cnstr_shdsc_gcm_decap(desc, &ctx->cdata, ivsize, ctx->authsize, false);
+ dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma,
+- desc_bytes(desc), DMA_TO_DEVICE);
++ desc_bytes(desc), ctx->dir);
+
+ return 0;
+ }
+@@ -382,6 +388,7 @@ static int rfc4106_set_sh_desc(struct cr
+ {
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *jrdev = ctx->jrdev;
++ unsigned int ivsize = crypto_aead_ivsize(aead);
+ u32 *desc;
+ int rem_bytes = CAAM_DESC_BYTES_MAX - GCM_DESC_JOB_IO_LEN -
+ ctx->cdata.keylen;
+@@ -403,9 +410,10 @@ static int rfc4106_set_sh_desc(struct cr
+ }
+
+ desc = ctx->sh_desc_enc;
+- cnstr_shdsc_rfc4106_encap(desc, &ctx->cdata, ctx->authsize);
++ cnstr_shdsc_rfc4106_encap(desc, &ctx->cdata, ivsize, ctx->authsize,
++ false);
+ dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma,
+- desc_bytes(desc), DMA_TO_DEVICE);
++ desc_bytes(desc), ctx->dir);
+
+ /*
+ * Job Descriptor and Shared Descriptors
+@@ -420,9 +428,10 @@ static int rfc4106_set_sh_desc(struct cr
+ }
+
+ desc = ctx->sh_desc_dec;
+- cnstr_shdsc_rfc4106_decap(desc, &ctx->cdata, ctx->authsize);
++ cnstr_shdsc_rfc4106_decap(desc, &ctx->cdata, ivsize, ctx->authsize,
++ false);
+ dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma,
+- desc_bytes(desc), DMA_TO_DEVICE);
++ desc_bytes(desc), ctx->dir);
+
+ return 0;
+ }
+@@ -442,6 +451,7 @@ static int rfc4543_set_sh_desc(struct cr
+ {
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *jrdev = ctx->jrdev;
++ unsigned int ivsize = crypto_aead_ivsize(aead);
+ u32 *desc;
+ int rem_bytes = CAAM_DESC_BYTES_MAX - GCM_DESC_JOB_IO_LEN -
+ ctx->cdata.keylen;
+@@ -463,9 +473,10 @@ static int rfc4543_set_sh_desc(struct cr
+ }
+
+ desc = ctx->sh_desc_enc;
+- cnstr_shdsc_rfc4543_encap(desc, &ctx->cdata, ctx->authsize);
++ cnstr_shdsc_rfc4543_encap(desc, &ctx->cdata, ivsize, ctx->authsize,
++ false);
+ dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma,
+- desc_bytes(desc), DMA_TO_DEVICE);
++ desc_bytes(desc), ctx->dir);
+
+ /*
+ * Job Descriptor and Shared Descriptors
+@@ -480,9 +491,10 @@ static int rfc4543_set_sh_desc(struct cr
+ }
+
+ desc = ctx->sh_desc_dec;
+- cnstr_shdsc_rfc4543_decap(desc, &ctx->cdata, ctx->authsize);
++ cnstr_shdsc_rfc4543_decap(desc, &ctx->cdata, ivsize, ctx->authsize,
++ false);
+ dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma,
+- desc_bytes(desc), DMA_TO_DEVICE);
++ desc_bytes(desc), ctx->dir);
+
+ return 0;
+ }
+@@ -503,6 +515,7 @@ static int aead_setkey(struct crypto_aea
+ {
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *jrdev = ctx->jrdev;
++ struct caam_drv_private *ctrlpriv = dev_get_drvdata(jrdev->parent);
+ struct crypto_authenc_keys keys;
+ int ret = 0;
+
+@@ -517,6 +530,27 @@ static int aead_setkey(struct crypto_aea
+ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
+ #endif
+
++ /*
++ * If DKP is supported, use it in the shared descriptor to generate
++ * the split key.
++ */
++ if (ctrlpriv->era >= 6) {
++ ctx->adata.keylen = keys.authkeylen;
++ ctx->adata.keylen_pad = split_key_len(ctx->adata.algtype &
++ OP_ALG_ALGSEL_MASK);
++
++ if (ctx->adata.keylen_pad + keys.enckeylen > CAAM_MAX_KEY_SIZE)
++ goto badkey;
++
++ memcpy(ctx->key, keys.authkey, keys.authkeylen);
++ memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey,
++ keys.enckeylen);
++ dma_sync_single_for_device(jrdev, ctx->key_dma,
++ ctx->adata.keylen_pad +
++ keys.enckeylen, ctx->dir);
++ goto skip_split_key;
++ }
++
+ ret = gen_split_key(ctx->jrdev, ctx->key, &ctx->adata, keys.authkey,
+ keys.authkeylen, CAAM_MAX_KEY_SIZE -
+ keys.enckeylen);
+@@ -527,12 +561,14 @@ static int aead_setkey(struct crypto_aea
+ /* postpend encryption key to auth split key */
+ memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen);
+ dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->adata.keylen_pad +
+- keys.enckeylen, DMA_TO_DEVICE);
++ keys.enckeylen, ctx->dir);
+ #ifdef DEBUG
+ print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, ctx->key,
+ ctx->adata.keylen_pad + keys.enckeylen, 1);
+ #endif
++
++skip_split_key:
+ ctx->cdata.keylen = keys.enckeylen;
+ return aead_set_sh_desc(aead);
+ badkey:
+@@ -552,7 +588,7 @@ static int gcm_setkey(struct crypto_aead
+ #endif
+
+ memcpy(ctx->key, key, keylen);
+- dma_sync_single_for_device(jrdev, ctx->key_dma, keylen, DMA_TO_DEVICE);
++ dma_sync_single_for_device(jrdev, ctx->key_dma, keylen, ctx->dir);
+ ctx->cdata.keylen = keylen;
+
+ return gcm_set_sh_desc(aead);
+@@ -580,7 +616,7 @@ static int rfc4106_setkey(struct crypto_
+ */
+ ctx->cdata.keylen = keylen - 4;
+ dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->cdata.keylen,
+- DMA_TO_DEVICE);
++ ctx->dir);
+ return rfc4106_set_sh_desc(aead);
+ }
+
+@@ -606,7 +642,7 @@ static int rfc4543_setkey(struct crypto_
+ */
+ ctx->cdata.keylen = keylen - 4;
+ dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->cdata.keylen,
+- DMA_TO_DEVICE);
++ ctx->dir);
+ return rfc4543_set_sh_desc(aead);
+ }
+
+@@ -658,21 +694,21 @@ static int ablkcipher_setkey(struct cryp
+ cnstr_shdsc_ablkcipher_encap(desc, &ctx->cdata, ivsize, is_rfc3686,
+ ctx1_iv_off);
+ dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma,
+- desc_bytes(desc), DMA_TO_DEVICE);
++ desc_bytes(desc), ctx->dir);
+
+ /* ablkcipher_decrypt shared descriptor */
+ desc = ctx->sh_desc_dec;
+ cnstr_shdsc_ablkcipher_decap(desc, &ctx->cdata, ivsize, is_rfc3686,
+ ctx1_iv_off);
+ dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma,
+- desc_bytes(desc), DMA_TO_DEVICE);
++ desc_bytes(desc), ctx->dir);
+
+ /* ablkcipher_givencrypt shared descriptor */
+ desc = ctx->sh_desc_givenc;
+ cnstr_shdsc_ablkcipher_givencap(desc, &ctx->cdata, ivsize, is_rfc3686,
+ ctx1_iv_off);
+ dma_sync_single_for_device(jrdev, ctx->sh_desc_givenc_dma,
+- desc_bytes(desc), DMA_TO_DEVICE);
++ desc_bytes(desc), ctx->dir);
+
+ return 0;
+ }
+@@ -701,13 +737,13 @@ static int xts_ablkcipher_setkey(struct
+ desc = ctx->sh_desc_enc;
+ cnstr_shdsc_xts_ablkcipher_encap(desc, &ctx->cdata);
+ dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma,
+- desc_bytes(desc), DMA_TO_DEVICE);
++ desc_bytes(desc), ctx->dir);
+
+ /* xts_ablkcipher_decrypt shared descriptor */
+ desc = ctx->sh_desc_dec;
+ cnstr_shdsc_xts_ablkcipher_decap(desc, &ctx->cdata);
+ dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma,
+- desc_bytes(desc), DMA_TO_DEVICE);
++ desc_bytes(desc), ctx->dir);
+
+ return 0;
+ }
+@@ -987,9 +1023,6 @@ static void init_aead_job(struct aead_re
+ append_seq_out_ptr(desc, dst_dma,
+ req->assoclen + req->cryptlen - authsize,
+ out_options);
+-
+- /* REG3 = assoclen */
+- append_math_add_imm_u32(desc, REG3, ZERO, IMM, req->assoclen);
+ }
+
+ static void init_gcm_job(struct aead_request *req,
+@@ -1004,6 +1037,7 @@ static void init_gcm_job(struct aead_req
+ unsigned int last;
+
+ init_aead_job(req, edesc, all_contig, encrypt);
++ append_math_add_imm_u32(desc, REG3, ZERO, IMM, req->assoclen);
+
+ /* BUG This should not be specific to generic GCM. */
+ last = 0;
+@@ -1030,6 +1064,7 @@ static void init_authenc_job(struct aead
+ struct caam_aead_alg, aead);
+ unsigned int ivsize = crypto_aead_ivsize(aead);
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
++ struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctx->jrdev->parent);
+ const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) ==
+ OP_ALG_AAI_CTR_MOD128);
+ const bool is_rfc3686 = alg->caam.rfc3686;
+@@ -1053,6 +1088,15 @@ static void init_authenc_job(struct aead
+
+ init_aead_job(req, edesc, all_contig, encrypt);
+
++ /*
++ * {REG3, DPOVRD} = assoclen, depending on whether MATH command supports
++ * having DPOVRD as destination.
++ */
++ if (ctrlpriv->era < 3)
++ append_math_add_imm_u32(desc, REG3, ZERO, IMM, req->assoclen);
++ else
++ append_math_add_imm_u32(desc, DPOVRD, ZERO, IMM, req->assoclen);
++
+ if (ivsize && ((is_rfc3686 && encrypt) || !alg->caam.geniv))
+ append_load_as_imm(desc, req->iv, ivsize,
+ LDST_CLASS_1_CCB |
+@@ -3203,9 +3247,11 @@ struct caam_crypto_alg {
+ struct caam_alg_entry caam;
+ };
+
+-static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam)
++static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam,
++ bool uses_dkp)
+ {
+ dma_addr_t dma_addr;
++ struct caam_drv_private *priv;
+
+ ctx->jrdev = caam_jr_alloc();
+ if (IS_ERR(ctx->jrdev)) {
+@@ -3213,10 +3259,16 @@ static int caam_init_common(struct caam_
+ return PTR_ERR(ctx->jrdev);
+ }
+
++ priv = dev_get_drvdata(ctx->jrdev->parent);
++ if (priv->era >= 6 && uses_dkp)
++ ctx->dir = DMA_BIDIRECTIONAL;
++ else
++ ctx->dir = DMA_TO_DEVICE;
++
+ dma_addr = dma_map_single_attrs(ctx->jrdev, ctx->sh_desc_enc,
+ offsetof(struct caam_ctx,
+ sh_desc_enc_dma),
+- DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
++ ctx->dir, DMA_ATTR_SKIP_CPU_SYNC);
+ if (dma_mapping_error(ctx->jrdev, dma_addr)) {
+ dev_err(ctx->jrdev, "unable to map key, shared descriptors\n");
+ caam_jr_free(ctx->jrdev);
+@@ -3244,7 +3296,7 @@ static int caam_cra_init(struct crypto_t
+ container_of(alg, struct caam_crypto_alg, crypto_alg);
+ struct caam_ctx *ctx = crypto_tfm_ctx(tfm);
+
+- return caam_init_common(ctx, &caam_alg->caam);
++ return caam_init_common(ctx, &caam_alg->caam, false);
+ }
+
+ static int caam_aead_init(struct crypto_aead *tfm)
+@@ -3254,14 +3306,15 @@ static int caam_aead_init(struct crypto_
+ container_of(alg, struct caam_aead_alg, aead);
+ struct caam_ctx *ctx = crypto_aead_ctx(tfm);
+
+- return caam_init_common(ctx, &caam_alg->caam);
++ return caam_init_common(ctx, &caam_alg->caam,
++ alg->setkey == aead_setkey);
+ }
+
+ static void caam_exit_common(struct caam_ctx *ctx)
+ {
+ dma_unmap_single_attrs(ctx->jrdev, ctx->sh_desc_enc_dma,
+ offsetof(struct caam_ctx, sh_desc_enc_dma),
+- DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
++ ctx->dir, DMA_ATTR_SKIP_CPU_SYNC);
+ caam_jr_free(ctx->jrdev);
+ }
+
+--- a/drivers/crypto/caam/caamalg_desc.c
++++ b/drivers/crypto/caam/caamalg_desc.c
+@@ -45,16 +45,16 @@ static inline void append_dec_op1(u32 *d
+ * cnstr_shdsc_aead_null_encap - IPSec ESP encapsulation shared descriptor
+ * (non-protocol) with no (null) encryption.
+ * @desc: pointer to buffer used for descriptor construction
+- * @adata: pointer to authentication transform definitions. Note that since a
+- * split key is to be used, the size of the split key itself is
+- * specified. Valid algorithm values - one of OP_ALG_ALGSEL_{MD5, SHA1,
+- * SHA224, SHA256, SHA384, SHA512} ANDed with OP_ALG_AAI_HMAC_PRECOMP.
++ * @adata: pointer to authentication transform definitions.
++ * A split key is required for SEC Era < 6; the size of the split key
++ * is specified in this case. Valid algorithm values - one of
++ * OP_ALG_ALGSEL_{MD5, SHA1, SHA224, SHA256, SHA384, SHA512} ANDed
++ * with OP_ALG_AAI_HMAC_PRECOMP.
+ * @icvsize: integrity check value (ICV) size (truncated or full)
+- *
+- * Note: Requires an MDHA split key.
++ * @era: SEC Era
+ */
+ void cnstr_shdsc_aead_null_encap(u32 * const desc, struct alginfo *adata,
+- unsigned int icvsize)
++ unsigned int icvsize, int era)
+ {
+ u32 *key_jump_cmd, *read_move_cmd, *write_move_cmd;
+
+@@ -63,13 +63,18 @@ void cnstr_shdsc_aead_null_encap(u32 * c
+ /* Skip if already shared */
+ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
+ JUMP_COND_SHRD);
+- if (adata->key_inline)
+- append_key_as_imm(desc, adata->key_virt, adata->keylen_pad,
+- adata->keylen, CLASS_2 | KEY_DEST_MDHA_SPLIT |
+- KEY_ENC);
+- else
+- append_key(desc, adata->key_dma, adata->keylen, CLASS_2 |
+- KEY_DEST_MDHA_SPLIT | KEY_ENC);
++ if (era < 6) {
++ if (adata->key_inline)
++ append_key_as_imm(desc, adata->key_virt,
++ adata->keylen_pad, adata->keylen,
++ CLASS_2 | KEY_DEST_MDHA_SPLIT |
++ KEY_ENC);
++ else
++ append_key(desc, adata->key_dma, adata->keylen,
++ CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC);
++ } else {
++ append_proto_dkp(desc, adata);
++ }
+ set_jump_tgt_here(desc, key_jump_cmd);
+
+ /* assoclen + cryptlen = seqinlen */
+@@ -121,16 +126,16 @@ EXPORT_SYMBOL(cnstr_shdsc_aead_null_enca
+ * cnstr_shdsc_aead_null_decap - IPSec ESP decapsulation shared descriptor
+ * (non-protocol) with no (null) decryption.
+ * @desc: pointer to buffer used for descriptor construction
+- * @adata: pointer to authentication transform definitions. Note that since a
+- * split key is to be used, the size of the split key itself is
+- * specified. Valid algorithm values - one of OP_ALG_ALGSEL_{MD5, SHA1,
+- * SHA224, SHA256, SHA384, SHA512} ANDed with OP_ALG_AAI_HMAC_PRECOMP.
++ * @adata: pointer to authentication transform definitions.
++ * A split key is required for SEC Era < 6; the size of the split key
++ * is specified in this case. Valid algorithm values - one of
++ * OP_ALG_ALGSEL_{MD5, SHA1, SHA224, SHA256, SHA384, SHA512} ANDed
++ * with OP_ALG_AAI_HMAC_PRECOMP.
+ * @icvsize: integrity check value (ICV) size (truncated or full)
+- *
+- * Note: Requires an MDHA split key.
++ * @era: SEC Era
+ */
+ void cnstr_shdsc_aead_null_decap(u32 * const desc, struct alginfo *adata,
+- unsigned int icvsize)
++ unsigned int icvsize, int era)
+ {
+ u32 *key_jump_cmd, *read_move_cmd, *write_move_cmd, *jump_cmd;
+
+@@ -139,13 +144,18 @@ void cnstr_shdsc_aead_null_decap(u32 * c
+ /* Skip if already shared */
+ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
+ JUMP_COND_SHRD);
+- if (adata->key_inline)
+- append_key_as_imm(desc, adata->key_virt, adata->keylen_pad,
+- adata->keylen, CLASS_2 |
+- KEY_DEST_MDHA_SPLIT | KEY_ENC);
+- else
+- append_key(desc, adata->key_dma, adata->keylen, CLASS_2 |
+- KEY_DEST_MDHA_SPLIT | KEY_ENC);
++ if (era < 6) {
++ if (adata->key_inline)
++ append_key_as_imm(desc, adata->key_virt,
++ adata->keylen_pad, adata->keylen,
++ CLASS_2 | KEY_DEST_MDHA_SPLIT |
++ KEY_ENC);
++ else
++ append_key(desc, adata->key_dma, adata->keylen,
++ CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC);
++ } else {
++ append_proto_dkp(desc, adata);
++ }
+ set_jump_tgt_here(desc, key_jump_cmd);
+
+ /* Class 2 operation */
+@@ -204,7 +214,7 @@ EXPORT_SYMBOL(cnstr_shdsc_aead_null_deca
+ static void init_sh_desc_key_aead(u32 * const desc,
+ struct alginfo * const cdata,
+ struct alginfo * const adata,
+- const bool is_rfc3686, u32 *nonce)
++ const bool is_rfc3686, u32 *nonce, int era)
+ {
+ u32 *key_jump_cmd;
+ unsigned int enckeylen = cdata->keylen;
+@@ -224,13 +234,18 @@ static void init_sh_desc_key_aead(u32 *
+ if (is_rfc3686)
+ enckeylen -= CTR_RFC3686_NONCE_SIZE;
+
+- if (adata->key_inline)
+- append_key_as_imm(desc, adata->key_virt, adata->keylen_pad,
+- adata->keylen, CLASS_2 |
+- KEY_DEST_MDHA_SPLIT | KEY_ENC);
+- else
+- append_key(desc, adata->key_dma, adata->keylen, CLASS_2 |
+- KEY_DEST_MDHA_SPLIT | KEY_ENC);
++ if (era < 6) {
++ if (adata->key_inline)
++ append_key_as_imm(desc, adata->key_virt,
++ adata->keylen_pad, adata->keylen,
++ CLASS_2 | KEY_DEST_MDHA_SPLIT |
++ KEY_ENC);
++ else
++ append_key(desc, adata->key_dma, adata->keylen,
++ CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC);
++ } else {
++ append_proto_dkp(desc, adata);
++ }
+
+ if (cdata->key_inline)
+ append_key_as_imm(desc, cdata->key_virt, enckeylen,
+@@ -261,26 +276,27 @@ static void init_sh_desc_key_aead(u32 *
+ * @cdata: pointer to block cipher transform definitions
+ * Valid algorithm values - one of OP_ALG_ALGSEL_{AES, DES, 3DES} ANDed
+ * with OP_ALG_AAI_CBC or OP_ALG_AAI_CTR_MOD128.
+- * @adata: pointer to authentication transform definitions. Note that since a
+- * split key is to be used, the size of the split key itself is
+- * specified. Valid algorithm values - one of OP_ALG_ALGSEL_{MD5, SHA1,
+- * SHA224, SHA256, SHA384, SHA512} ANDed with OP_ALG_AAI_HMAC_PRECOMP.
++ * @adata: pointer to authentication transform definitions.
++ * A split key is required for SEC Era < 6; the size of the split key
++ * is specified in this case. Valid algorithm values - one of
++ * OP_ALG_ALGSEL_{MD5, SHA1, SHA224, SHA256, SHA384, SHA512} ANDed
++ * with OP_ALG_AAI_HMAC_PRECOMP.
+ * @ivsize: initialization vector size
+ * @icvsize: integrity check value (ICV) size (truncated or full)
+ * @is_rfc3686: true when ctr(aes) is wrapped by rfc3686 template
+ * @nonce: pointer to rfc3686 nonce
+ * @ctx1_iv_off: IV offset in CONTEXT1 register
+ * @is_qi: true when called from caam/qi
+- *
+- * Note: Requires an MDHA split key.
++ * @era: SEC Era
+ */
+ void cnstr_shdsc_aead_encap(u32 * const desc, struct alginfo *cdata,
+ struct alginfo *adata, unsigned int ivsize,
+ unsigned int icvsize, const bool is_rfc3686,
+- u32 *nonce, const u32 ctx1_iv_off, const bool is_qi)
++ u32 *nonce, const u32 ctx1_iv_off, const bool is_qi,
++ int era)
+ {
+ /* Note: Context registers are saved. */
+- init_sh_desc_key_aead(desc, cdata, adata, is_rfc3686, nonce);
++ init_sh_desc_key_aead(desc, cdata, adata, is_rfc3686, nonce, era);
+
+ /* Class 2 operation */
+ append_operation(desc, adata->algtype | OP_ALG_AS_INITFINAL |
+@@ -306,8 +322,13 @@ void cnstr_shdsc_aead_encap(u32 * const
+ }
+
+ /* Read and write assoclen bytes */
+- append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ);
+- append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ);
++ if (is_qi || era < 3) {
++ append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ);
++ append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ);
++ } else {
++ append_math_add(desc, VARSEQINLEN, ZERO, DPOVRD, CAAM_CMD_SZ);
++ append_math_add(desc, VARSEQOUTLEN, ZERO, DPOVRD, CAAM_CMD_SZ);
++ }
+
+ /* Skip assoc data */
+ append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF);
+@@ -350,27 +371,27 @@ EXPORT_SYMBOL(cnstr_shdsc_aead_encap);
+ * @cdata: pointer to block cipher transform definitions
+ * Valid algorithm values - one of OP_ALG_ALGSEL_{AES, DES, 3DES} ANDed
+ * with OP_ALG_AAI_CBC or OP_ALG_AAI_CTR_MOD128.
+- * @adata: pointer to authentication transform definitions. Note that since a
+- * split key is to be used, the size of the split key itself is
+- * specified. Valid algorithm values - one of OP_ALG_ALGSEL_{MD5, SHA1,
+- * SHA224, SHA256, SHA384, SHA512} ANDed with OP_ALG_AAI_HMAC_PRECOMP.
++ * @adata: pointer to authentication transform definitions.
++ * A split key is required for SEC Era < 6; the size of the split key
++ * is specified in this case. Valid algorithm values - one of
++ * OP_ALG_ALGSEL_{MD5, SHA1, SHA224, SHA256, SHA384, SHA512} ANDed
++ * with OP_ALG_AAI_HMAC_PRECOMP.
+ * @ivsize: initialization vector size
+ * @icvsize: integrity check value (ICV) size (truncated or full)
+ * @is_rfc3686: true when ctr(aes) is wrapped by rfc3686 template
+ * @nonce: pointer to rfc3686 nonce
+ * @ctx1_iv_off: IV offset in CONTEXT1 register
+ * @is_qi: true when called from caam/qi
+- *
+- * Note: Requires an MDHA split key.
++ * @era: SEC Era
+ */
+ void cnstr_shdsc_aead_decap(u32 * const desc, struct alginfo *cdata,
+ struct alginfo *adata, unsigned int ivsize,
+ unsigned int icvsize, const bool geniv,
+ const bool is_rfc3686, u32 *nonce,
+- const u32 ctx1_iv_off, const bool is_qi)
++ const u32 ctx1_iv_off, const bool is_qi, int era)
+ {
+ /* Note: Context registers are saved. */
+- init_sh_desc_key_aead(desc, cdata, adata, is_rfc3686, nonce);
++ init_sh_desc_key_aead(desc, cdata, adata, is_rfc3686, nonce, era);
+
+ /* Class 2 operation */
+ append_operation(desc, adata->algtype | OP_ALG_AS_INITFINAL |
+@@ -397,11 +418,23 @@ void cnstr_shdsc_aead_decap(u32 * const
+ }
+
+ /* Read and write assoclen bytes */
+- append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ);
+- if (geniv)
+- append_math_add_imm_u32(desc, VARSEQOUTLEN, REG3, IMM, ivsize);
+- else
+- append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ);
++ if (is_qi || era < 3) {
++ append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ);
++ if (geniv)
++ append_math_add_imm_u32(desc, VARSEQOUTLEN, REG3, IMM,
++ ivsize);
++ else
++ append_math_add(desc, VARSEQOUTLEN, ZERO, REG3,
++ CAAM_CMD_SZ);
++ } else {
++ append_math_add(desc, VARSEQINLEN, ZERO, DPOVRD, CAAM_CMD_SZ);
++ if (geniv)
++ append_math_add_imm_u32(desc, VARSEQOUTLEN, DPOVRD, IMM,
++ ivsize);
++ else
++ append_math_add(desc, VARSEQOUTLEN, ZERO, DPOVRD,
++ CAAM_CMD_SZ);
++ }
+
+ /* Skip assoc data */
+ append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF);
+@@ -456,29 +489,29 @@ EXPORT_SYMBOL(cnstr_shdsc_aead_decap);
+ * @cdata: pointer to block cipher transform definitions
+ * Valid algorithm values - one of OP_ALG_ALGSEL_{AES, DES, 3DES} ANDed
+ * with OP_ALG_AAI_CBC or OP_ALG_AAI_CTR_MOD128.
+- * @adata: pointer to authentication transform definitions. Note that since a
+- * split key is to be used, the size of the split key itself is
+- * specified. Valid algorithm values - one of OP_ALG_ALGSEL_{MD5, SHA1,
+- * SHA224, SHA256, SHA384, SHA512} ANDed with OP_ALG_AAI_HMAC_PRECOMP.
++ * @adata: pointer to authentication transform definitions.
++ * A split key is required for SEC Era < 6; the size of the split key
++ * is specified in this case. Valid algorithm values - one of
++ * OP_ALG_ALGSEL_{MD5, SHA1, SHA224, SHA256, SHA384, SHA512} ANDed
++ * with OP_ALG_AAI_HMAC_PRECOMP.
+ * @ivsize: initialization vector size
+ * @icvsize: integrity check value (ICV) size (truncated or full)
+ * @is_rfc3686: true when ctr(aes) is wrapped by rfc3686 template
+ * @nonce: pointer to rfc3686 nonce
+ * @ctx1_iv_off: IV offset in CONTEXT1 register
+ * @is_qi: true when called from caam/qi
+- *
+- * Note: Requires an MDHA split key.
++ * @era: SEC Era
+ */
+ void cnstr_shdsc_aead_givencap(u32 * const desc, struct alginfo *cdata,
+ struct alginfo *adata, unsigned int ivsize,
+ unsigned int icvsize, const bool is_rfc3686,
+ u32 *nonce, const u32 ctx1_iv_off,
+- const bool is_qi)
++ const bool is_qi, int era)
+ {
+ u32 geniv, moveiv;
+
+ /* Note: Context registers are saved. */
+- init_sh_desc_key_aead(desc, cdata, adata, is_rfc3686, nonce);
++ init_sh_desc_key_aead(desc, cdata, adata, is_rfc3686, nonce, era);
+
+ if (is_qi) {
+ u32 *wait_load_cmd;
+@@ -528,8 +561,13 @@ copy_iv:
+ OP_ALG_ENCRYPT);
+
+ /* Read and write assoclen bytes */
+- append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ);
+- append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ);
++ if (is_qi || era < 3) {
++ append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ);
++ append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ);
++ } else {
++ append_math_add(desc, VARSEQINLEN, ZERO, DPOVRD, CAAM_CMD_SZ);
++ append_math_add(desc, VARSEQOUTLEN, ZERO, DPOVRD, CAAM_CMD_SZ);
++ }
+
+ /* Skip assoc data */
+ append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF);
+@@ -583,14 +621,431 @@ copy_iv:
+ EXPORT_SYMBOL(cnstr_shdsc_aead_givencap);
+
+ /**
++ * cnstr_shdsc_tls_encap - tls encapsulation shared descriptor
++ * @desc: pointer to buffer used for descriptor construction
++ * @cdata: pointer to block cipher transform definitions
++ * Valid algorithm values - one of OP_ALG_ALGSEL_AES ANDed
++ * with OP_ALG_AAI_CBC
++ * @adata: pointer to authentication transform definitions.
++ * A split key is required for SEC Era < 6; the size of the split key
++ * is specified in this case. Valid algorithm values OP_ALG_ALGSEL_SHA1
++ * ANDed with OP_ALG_AAI_HMAC_PRECOMP.
++ * @assoclen: associated data length
++ * @ivsize: initialization vector size
++ * @authsize: authentication data size
++ * @blocksize: block cipher size
++ * @era: SEC Era
++ */
++void cnstr_shdsc_tls_encap(u32 * const desc, struct alginfo *cdata,
++ struct alginfo *adata, unsigned int assoclen,
++ unsigned int ivsize, unsigned int authsize,
++ unsigned int blocksize, int era)
++{
++ u32 *key_jump_cmd, *zero_payload_jump_cmd;
++ u32 genpad, idx_ld_datasz, idx_ld_pad, stidx;
++
++ /*
++ * Compute the index (in bytes) for the LOAD with destination of
++ * Class 1 Data Size Register and for the LOAD that generates padding
++ */
++ if (adata->key_inline) {
++ idx_ld_datasz = DESC_TLS10_ENC_LEN + adata->keylen_pad +
++ cdata->keylen - 4 * CAAM_CMD_SZ;
++ idx_ld_pad = DESC_TLS10_ENC_LEN + adata->keylen_pad +
++ cdata->keylen - 2 * CAAM_CMD_SZ;
++ } else {
++ idx_ld_datasz = DESC_TLS10_ENC_LEN + 2 * CAAM_PTR_SZ -
++ 4 * CAAM_CMD_SZ;
++ idx_ld_pad = DESC_TLS10_ENC_LEN + 2 * CAAM_PTR_SZ -
++ 2 * CAAM_CMD_SZ;
++ }
++
++ stidx = 1 << HDR_START_IDX_SHIFT;
++ init_sh_desc(desc, HDR_SHARE_SERIAL | stidx);
++
++ /* skip key loading if they are loaded due to sharing */
++ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
++ JUMP_COND_SHRD);
++
++ if (era < 6) {
++ if (adata->key_inline)
++ append_key_as_imm(desc, adata->key_virt,
++ adata->keylen_pad, adata->keylen,
++ CLASS_2 | KEY_DEST_MDHA_SPLIT |
++ KEY_ENC);
++ else
++ append_key(desc, adata->key_dma, adata->keylen,
++ CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC);
++ } else {
++ append_proto_dkp(desc, adata);
++ }
++
++ if (cdata->key_inline)
++ append_key_as_imm(desc, cdata->key_virt, cdata->keylen,
++ cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG);
++ else
++ append_key(desc, cdata->key_dma, cdata->keylen, CLASS_1 |
++ KEY_DEST_CLASS_REG);
++
++ set_jump_tgt_here(desc, key_jump_cmd);
++
++ /* class 2 operation */
++ append_operation(desc, adata->algtype | OP_ALG_AS_INITFINAL |
++ OP_ALG_ENCRYPT);
++ /* class 1 operation */
++ append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL |
++ OP_ALG_ENCRYPT);
++
++ /* payloadlen = input data length - (assoclen + ivlen) */
++ append_math_sub_imm_u32(desc, REG0, SEQINLEN, IMM, assoclen + ivsize);
++
++ /* math1 = payloadlen + icvlen */
++ append_math_add_imm_u32(desc, REG1, REG0, IMM, authsize);
++
++ /* padlen = block_size - math1 % block_size */
++ append_math_and_imm_u32(desc, REG3, REG1, IMM, blocksize - 1);
++ append_math_sub_imm_u32(desc, REG2, IMM, REG3, blocksize);
++
++ /* cryptlen = payloadlen + icvlen + padlen */
++ append_math_add(desc, VARSEQOUTLEN, REG1, REG2, 4);
++
++ /*
++ * update immediate data with the padding length value
++ * for the LOAD in the class 1 data size register.
++ */
++ append_move(desc, MOVE_SRC_DESCBUF | MOVE_DEST_MATH2 |
++ (idx_ld_datasz << MOVE_OFFSET_SHIFT) | 7);
++ append_move(desc, MOVE_WAITCOMP | MOVE_SRC_MATH2 | MOVE_DEST_DESCBUF |
++ (idx_ld_datasz << MOVE_OFFSET_SHIFT) | 8);
++
++ /* overwrite PL field for the padding iNFO FIFO entry */
++ append_move(desc, MOVE_SRC_DESCBUF | MOVE_DEST_MATH2 |
++ (idx_ld_pad << MOVE_OFFSET_SHIFT) | 7);
++ append_move(desc, MOVE_WAITCOMP | MOVE_SRC_MATH2 | MOVE_DEST_DESCBUF |
++ (idx_ld_pad << MOVE_OFFSET_SHIFT) | 8);
++
++ /* store encrypted payload, icv and padding */
++ append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | LDST_VLF);
++
++ /* if payload length is zero, jump to zero-payload commands */
++ append_math_add(desc, VARSEQINLEN, ZERO, REG0, 4);
++ zero_payload_jump_cmd = append_jump(desc, JUMP_TEST_ALL |
++ JUMP_COND_MATH_Z);
++
++ /* load iv in context1 */
++ append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_WORD_CLASS_CTX |
++ LDST_CLASS_1_CCB | ivsize);
++
++ /* read assoc for authentication */
++ append_seq_fifo_load(desc, assoclen, FIFOLD_CLASS_CLASS2 |
++ FIFOLD_TYPE_MSG);
++ /* insnoop payload */
++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH | FIFOLD_TYPE_MSG |
++ FIFOLD_TYPE_LAST2 | FIFOLDST_VLF);
++
++ /* jump the zero-payload commands */
++ append_jump(desc, JUMP_TEST_ALL | 3);
++
++ /* zero-payload commands */
++ set_jump_tgt_here(desc, zero_payload_jump_cmd);
++
++ /* load iv in context1 */
++ append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_WORD_CLASS_CTX |
++ LDST_CLASS_1_CCB | ivsize);
++
++ /* assoc data is the only data for authentication */
++ append_seq_fifo_load(desc, assoclen, FIFOLD_CLASS_CLASS2 |
++ FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST2);
++
++ /* send icv to encryption */
++ append_move(desc, MOVE_SRC_CLASS2CTX | MOVE_DEST_CLASS1INFIFO |
++ authsize);
++
++ /* update class 1 data size register with padding length */
++ append_load_imm_u32(desc, 0, LDST_CLASS_1_CCB |
++ LDST_SRCDST_WORD_DATASZ_REG | LDST_IMM);
++
++ /* generate padding and send it to encryption */
++ genpad = NFIFOENTRY_DEST_CLASS1 | NFIFOENTRY_LC1 | NFIFOENTRY_FC1 |
++ NFIFOENTRY_STYPE_PAD | NFIFOENTRY_DTYPE_MSG | NFIFOENTRY_PTYPE_N;
++ append_load_imm_u32(desc, genpad, LDST_CLASS_IND_CCB |
++ LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM);
++
++#ifdef DEBUG
++ print_hex_dump(KERN_ERR, "tls enc shdesc@" __stringify(__LINE__) ": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, desc,
++ desc_bytes(desc), 1);
++#endif
++}
++EXPORT_SYMBOL(cnstr_shdsc_tls_encap);
++
++/**
++ * cnstr_shdsc_tls_decap - tls decapsulation shared descriptor
++ * @desc: pointer to buffer used for descriptor construction
++ * @cdata: pointer to block cipher transform definitions
++ * Valid algorithm values - one of OP_ALG_ALGSEL_AES ANDed
++ * with OP_ALG_AAI_CBC
++ * @adata: pointer to authentication transform definitions.
++ * A split key is required for SEC Era < 6; the size of the split key
++ * is specified in this case. Valid algorithm values OP_ALG_ALGSEL_SHA1
++ * ANDed with OP_ALG_AAI_HMAC_PRECOMP.
++ * @assoclen: associated data length
++ * @ivsize: initialization vector size
++ * @authsize: authentication data size
++ * @blocksize: block cipher size
++ * @era: SEC Era
++ */
++void cnstr_shdsc_tls_decap(u32 * const desc, struct alginfo *cdata,
++ struct alginfo *adata, unsigned int assoclen,
++ unsigned int ivsize, unsigned int authsize,
++ unsigned int blocksize, int era)
++{
++ u32 stidx, jumpback;
++ u32 *key_jump_cmd, *zero_payload_jump_cmd, *skip_zero_jump_cmd;
++ /*
++ * Pointer Size bool determines the size of address pointers.
++ * false - Pointers fit in one 32-bit word.
++ * true - Pointers fit in two 32-bit words.
++ */
++ static const bool ps = (CAAM_PTR_SZ != CAAM_CMD_SZ);
++
++ stidx = 1 << HDR_START_IDX_SHIFT;
++ init_sh_desc(desc, HDR_SHARE_SERIAL | stidx);
++
++ /* skip key loading if they are loaded due to sharing */
++ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
++ JUMP_COND_SHRD);
++
++ if (era < 6)
++ append_key(desc, adata->key_dma, adata->keylen, CLASS_2 |
++ KEY_DEST_MDHA_SPLIT | KEY_ENC);
++ else
++ append_proto_dkp(desc, adata);
++
++ append_key(desc, cdata->key_dma, cdata->keylen, CLASS_1 |
++ KEY_DEST_CLASS_REG);
++
++ set_jump_tgt_here(desc, key_jump_cmd);
++
++ /* class 2 operation */
++ append_operation(desc, adata->algtype | OP_ALG_AS_INITFINAL |
++ OP_ALG_DECRYPT | OP_ALG_ICV_ON);
++ /* class 1 operation */
++ append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL |
++ OP_ALG_DECRYPT);
++
++ /* VSIL = input data length - 2 * block_size */
++ append_math_sub_imm_u32(desc, VARSEQINLEN, SEQINLEN, IMM, 2 *
++ blocksize);
++
++ /*
++ * payloadlen + icvlen + padlen = input data length - (assoclen +
++ * ivsize)
++ */
++ append_math_sub_imm_u32(desc, REG3, SEQINLEN, IMM, assoclen + ivsize);
++
++ /* skip data to the last but one cipher block */
++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_SKIP | LDST_VLF);
++
++ /* load iv for the last cipher block */
++ append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_WORD_CLASS_CTX |
++ LDST_CLASS_1_CCB | ivsize);
++
++ /* read last cipher block */
++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_MSG |
++ FIFOLD_TYPE_LAST1 | blocksize);
++
++ /* move decrypted block into math0 and math1 */
++ append_move(desc, MOVE_WAITCOMP | MOVE_SRC_OUTFIFO | MOVE_DEST_MATH0 |
++ blocksize);
++
++ /* reset AES CHA */
++ append_load_imm_u32(desc, CCTRL_RESET_CHA_AESA, LDST_CLASS_IND_CCB |
++ LDST_SRCDST_WORD_CHACTRL | LDST_IMM);
++
++ /* rewind input sequence */
++ append_seq_in_ptr_intlen(desc, 0, 65535, SQIN_RTO);
++
++ /* key1 is in decryption form */
++ append_operation(desc, cdata->algtype | OP_ALG_AAI_DK |
++ OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT);
++
++ /* load iv in context1 */
++ append_cmd(desc, CMD_SEQ_LOAD | LDST_CLASS_1_CCB |
++ LDST_SRCDST_WORD_CLASS_CTX | ivsize);
++
++ /* read sequence number */
++ append_seq_fifo_load(desc, 8, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG);
++ /* load Type, Version and Len fields in math0 */
++ append_cmd(desc, CMD_SEQ_LOAD | LDST_CLASS_DECO |
++ LDST_SRCDST_WORD_DECO_MATH0 | (3 << LDST_OFFSET_SHIFT) | 5);
++
++ /* compute (padlen - 1) */
++ append_math_and_imm_u64(desc, REG1, REG1, IMM, 255);
++
++ /* math2 = icvlen + (padlen - 1) + 1 */
++ append_math_add_imm_u32(desc, REG2, REG1, IMM, authsize + 1);
++
++ append_jump(desc, JUMP_TEST_ALL | JUMP_COND_CALM | 1);
++
++ /* VSOL = payloadlen + icvlen + padlen */
++ append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, 4);
++
++ if (caam_little_end)
++ append_moveb(desc, MOVE_WAITCOMP |
++ MOVE_SRC_MATH0 | MOVE_DEST_MATH0 | 8);
++
++ /* update Len field */
++ append_math_sub(desc, REG0, REG0, REG2, 8);
++
++ /* store decrypted payload, icv and padding */
++ append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | LDST_VLF);
++
++ /* VSIL = (payloadlen + icvlen + padlen) - (icvlen + padlen)*/
++ append_math_sub(desc, VARSEQINLEN, REG3, REG2, 4);
++
++ zero_payload_jump_cmd = append_jump(desc, JUMP_TEST_ALL |
++ JUMP_COND_MATH_Z);
++
++ /* send Type, Version and Len(pre ICV) fields to authentication */
++ append_move(desc, MOVE_WAITCOMP |
++ MOVE_SRC_MATH0 | MOVE_DEST_CLASS2INFIFO |
++ (3 << MOVE_OFFSET_SHIFT) | 5);
++
++ /* outsnooping payload */
++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH |
++ FIFOLD_TYPE_MSG1OUT2 | FIFOLD_TYPE_LAST2 |
++ FIFOLDST_VLF);
++ skip_zero_jump_cmd = append_jump(desc, JUMP_TEST_ALL | 2);
++
++ set_jump_tgt_here(desc, zero_payload_jump_cmd);
++ /* send Type, Version and Len(pre ICV) fields to authentication */
++ append_move(desc, MOVE_WAITCOMP | MOVE_AUX_LS |
++ MOVE_SRC_MATH0 | MOVE_DEST_CLASS2INFIFO |
++ (3 << MOVE_OFFSET_SHIFT) | 5);
++
++ set_jump_tgt_here(desc, skip_zero_jump_cmd);
++ append_math_add(desc, VARSEQINLEN, ZERO, REG2, 4);
++
++ /* load icvlen and padlen */
++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_MSG |
++ FIFOLD_TYPE_LAST1 | FIFOLDST_VLF);
++
++ /* VSIL = (payloadlen + icvlen + padlen) - icvlen + padlen */
++ append_math_sub(desc, VARSEQINLEN, REG3, REG2, 4);
++
++ /*
++ * Start a new input sequence using the SEQ OUT PTR command options,
++ * pointer and length used when the current output sequence was defined.
++ */
++ if (ps) {
++ /*
++ * Move the lower 32 bits of Shared Descriptor address, the
++ * SEQ OUT PTR command, Output Pointer (2 words) and
++ * Output Length into math registers.
++ */
++ if (caam_little_end)
++ append_move(desc, MOVE_WAITCOMP | MOVE_SRC_DESCBUF |
++ MOVE_DEST_MATH0 |
++ (55 * 4 << MOVE_OFFSET_SHIFT) | 20);
++ else
++ append_move(desc, MOVE_WAITCOMP | MOVE_SRC_DESCBUF |
++ MOVE_DEST_MATH0 |
++ (54 * 4 << MOVE_OFFSET_SHIFT) | 20);
++
++ /* Transform SEQ OUT PTR command in SEQ IN PTR command */
++ append_math_and_imm_u32(desc, REG0, REG0, IMM,
++ ~(CMD_SEQ_IN_PTR ^ CMD_SEQ_OUT_PTR));
++ /* Append a JUMP command after the copied fields */
++ jumpback = CMD_JUMP | (char)-9;
++ append_load_imm_u32(desc, jumpback, LDST_CLASS_DECO | LDST_IMM |
++ LDST_SRCDST_WORD_DECO_MATH2 |
++ (4 << LDST_OFFSET_SHIFT));
++ append_jump(desc, JUMP_TEST_ALL | JUMP_COND_CALM | 1);
++ /* Move the updated fields back to the Job Descriptor */
++ if (caam_little_end)
++ append_move(desc, MOVE_WAITCOMP | MOVE_SRC_MATH0 |
++ MOVE_DEST_DESCBUF |
++ (55 * 4 << MOVE_OFFSET_SHIFT) | 24);
++ else
++ append_move(desc, MOVE_WAITCOMP | MOVE_SRC_MATH0 |
++ MOVE_DEST_DESCBUF |
++ (54 * 4 << MOVE_OFFSET_SHIFT) | 24);
++
++ /*
++ * Read the new SEQ IN PTR command, Input Pointer, Input Length
++ * and then jump back to the next command from the
++ * Shared Descriptor.
++ */
++ append_jump(desc, JUMP_TEST_ALL | JUMP_COND_CALM | 6);
++ } else {
++ /*
++ * Move the SEQ OUT PTR command, Output Pointer (1 word) and
++ * Output Length into math registers.
++ */
++ if (caam_little_end)
++ append_move(desc, MOVE_WAITCOMP | MOVE_SRC_DESCBUF |
++ MOVE_DEST_MATH0 |
++ (54 * 4 << MOVE_OFFSET_SHIFT) | 12);
++ else
++ append_move(desc, MOVE_WAITCOMP | MOVE_SRC_DESCBUF |
++ MOVE_DEST_MATH0 |
++ (53 * 4 << MOVE_OFFSET_SHIFT) | 12);
++
++ /* Transform SEQ OUT PTR command in SEQ IN PTR command */
++ append_math_and_imm_u64(desc, REG0, REG0, IMM,
++ ~(((u64)(CMD_SEQ_IN_PTR ^
++ CMD_SEQ_OUT_PTR)) << 32));
++ /* Append a JUMP command after the copied fields */
++ jumpback = CMD_JUMP | (char)-7;
++ append_load_imm_u32(desc, jumpback, LDST_CLASS_DECO | LDST_IMM |
++ LDST_SRCDST_WORD_DECO_MATH1 |
++ (4 << LDST_OFFSET_SHIFT));
++ append_jump(desc, JUMP_TEST_ALL | JUMP_COND_CALM | 1);
++ /* Move the updated fields back to the Job Descriptor */
++ if (caam_little_end)
++ append_move(desc, MOVE_WAITCOMP | MOVE_SRC_MATH0 |
++ MOVE_DEST_DESCBUF |
++ (54 * 4 << MOVE_OFFSET_SHIFT) | 16);
++ else
++ append_move(desc, MOVE_WAITCOMP | MOVE_SRC_MATH0 |
++ MOVE_DEST_DESCBUF |
++ (53 * 4 << MOVE_OFFSET_SHIFT) | 16);
++
++ /*
++ * Read the new SEQ IN PTR command, Input Pointer, Input Length
++ * and then jump back to the next command from the
++ * Shared Descriptor.
++ */
++ append_jump(desc, JUMP_TEST_ALL | JUMP_COND_CALM | 5);
++ }
++
++ /* skip payload */
++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_SKIP | FIFOLDST_VLF);
++ /* check icv */
++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_ICV |
++ FIFOLD_TYPE_LAST2 | authsize);
++
++#ifdef DEBUG
++ print_hex_dump(KERN_ERR, "tls dec shdesc@" __stringify(__LINE__) ": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, desc,
++ desc_bytes(desc), 1);
++#endif
++}
++EXPORT_SYMBOL(cnstr_shdsc_tls_decap);
++
++/**
+ * cnstr_shdsc_gcm_encap - gcm encapsulation shared descriptor
+ * @desc: pointer to buffer used for descriptor construction
+ * @cdata: pointer to block cipher transform definitions
+ * Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM.
++ * @ivsize: initialization vector size
+ * @icvsize: integrity check value (ICV) size (truncated or full)
++ * @is_qi: true when called from caam/qi
+ */
+ void cnstr_shdsc_gcm_encap(u32 * const desc, struct alginfo *cdata,
+- unsigned int icvsize)
++ unsigned int ivsize, unsigned int icvsize,
++ const bool is_qi)
+ {
+ u32 *key_jump_cmd, *zero_payload_jump_cmd, *zero_assoc_jump_cmd1,
+ *zero_assoc_jump_cmd2;
+@@ -612,11 +1067,35 @@ void cnstr_shdsc_gcm_encap(u32 * const d
+ append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL |
+ OP_ALG_ENCRYPT);
+
++ if (is_qi) {
++ u32 *wait_load_cmd;
++
++ /* REG3 = assoclen */
++ append_seq_load(desc, 4, LDST_CLASS_DECO |
++ LDST_SRCDST_WORD_DECO_MATH3 |
++ (4 << LDST_OFFSET_SHIFT));
++
++ wait_load_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
++ JUMP_COND_CALM | JUMP_COND_NCP |
++ JUMP_COND_NOP | JUMP_COND_NIP |
++ JUMP_COND_NIFP);
++ set_jump_tgt_here(desc, wait_load_cmd);
++
++ append_math_sub_imm_u32(desc, VARSEQOUTLEN, SEQINLEN, IMM,
++ ivsize);
++ } else {
++ append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG0,
++ CAAM_CMD_SZ);
++ }
++
+ /* if assoclen + cryptlen is ZERO, skip to ICV write */
+- append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ);
+ zero_assoc_jump_cmd2 = append_jump(desc, JUMP_TEST_ALL |
+ JUMP_COND_MATH_Z);
+
++ if (is_qi)
++ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 |
++ FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1);
++
+ /* if assoclen is ZERO, skip reading the assoc data */
+ append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ);
+ zero_assoc_jump_cmd1 = append_jump(desc, JUMP_TEST_ALL |
+@@ -648,8 +1127,11 @@ void cnstr_shdsc_gcm_encap(u32 * const d
+ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF |
+ FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1);
+
+- /* jump the zero-payload commands */
+- append_jump(desc, JUMP_TEST_ALL | 2);
++ /* jump to ICV writing */
++ if (is_qi)
++ append_jump(desc, JUMP_TEST_ALL | 4);
++ else
++ append_jump(desc, JUMP_TEST_ALL | 2);
+
+ /* zero-payload commands */
+ set_jump_tgt_here(desc, zero_payload_jump_cmd);
+@@ -657,10 +1139,18 @@ void cnstr_shdsc_gcm_encap(u32 * const d
+ /* read assoc data */
+ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF |
+ FIFOLD_TYPE_AAD | FIFOLD_TYPE_LAST1);
++ if (is_qi)
++ /* jump to ICV writing */
++ append_jump(desc, JUMP_TEST_ALL | 2);
+
+ /* There is no input data */
+ set_jump_tgt_here(desc, zero_assoc_jump_cmd2);
+
++ if (is_qi)
++ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 |
++ FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1 |
++ FIFOLD_TYPE_LAST1);
++
+ /* write ICV */
+ append_seq_store(desc, icvsize, LDST_CLASS_1_CCB |
+ LDST_SRCDST_BYTE_CONTEXT);
+@@ -677,10 +1167,13 @@ EXPORT_SYMBOL(cnstr_shdsc_gcm_encap);
+ * @desc: pointer to buffer used for descriptor construction
+ * @cdata: pointer to block cipher transform definitions
+ * Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM.
++ * @ivsize: initialization vector size
+ * @icvsize: integrity check value (ICV) size (truncated or full)
++ * @is_qi: true when called from caam/qi
+ */
+ void cnstr_shdsc_gcm_decap(u32 * const desc, struct alginfo *cdata,
+- unsigned int icvsize)
++ unsigned int ivsize, unsigned int icvsize,
++ const bool is_qi)
+ {
+ u32 *key_jump_cmd, *zero_payload_jump_cmd, *zero_assoc_jump_cmd1;
+
+@@ -701,6 +1194,24 @@ void cnstr_shdsc_gcm_decap(u32 * const d
+ append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL |
+ OP_ALG_DECRYPT | OP_ALG_ICV_ON);
+
++ if (is_qi) {
++ u32 *wait_load_cmd;
++
++ /* REG3 = assoclen */
++ append_seq_load(desc, 4, LDST_CLASS_DECO |
++ LDST_SRCDST_WORD_DECO_MATH3 |
++ (4 << LDST_OFFSET_SHIFT));
++
++ wait_load_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
++ JUMP_COND_CALM | JUMP_COND_NCP |
++ JUMP_COND_NOP | JUMP_COND_NIP |
++ JUMP_COND_NIFP);
++ set_jump_tgt_here(desc, wait_load_cmd);
++
++ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 |
++ FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1);
++ }
++
+ /* if assoclen is ZERO, skip reading the assoc data */
+ append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ);
+ zero_assoc_jump_cmd1 = append_jump(desc, JUMP_TEST_ALL |
+@@ -753,10 +1264,13 @@ EXPORT_SYMBOL(cnstr_shdsc_gcm_decap);
+ * @desc: pointer to buffer used for descriptor construction
+ * @cdata: pointer to block cipher transform definitions
+ * Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM.
++ * @ivsize: initialization vector size
+ * @icvsize: integrity check value (ICV) size (truncated or full)
++ * @is_qi: true when called from caam/qi
+ */
+ void cnstr_shdsc_rfc4106_encap(u32 * const desc, struct alginfo *cdata,
+- unsigned int icvsize)
++ unsigned int ivsize, unsigned int icvsize,
++ const bool is_qi)
+ {
+ u32 *key_jump_cmd;
+
+@@ -777,7 +1291,29 @@ void cnstr_shdsc_rfc4106_encap(u32 * con
+ append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL |
+ OP_ALG_ENCRYPT);
+
+- append_math_sub_imm_u32(desc, VARSEQINLEN, REG3, IMM, 8);
++ if (is_qi) {
++ u32 *wait_load_cmd;
++
++ /* REG3 = assoclen */
++ append_seq_load(desc, 4, LDST_CLASS_DECO |
++ LDST_SRCDST_WORD_DECO_MATH3 |
++ (4 << LDST_OFFSET_SHIFT));
++
++ wait_load_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
++ JUMP_COND_CALM | JUMP_COND_NCP |
++ JUMP_COND_NOP | JUMP_COND_NIP |
++ JUMP_COND_NIFP);
++ set_jump_tgt_here(desc, wait_load_cmd);
++
++ /* Read salt and IV */
++ append_fifo_load_as_imm(desc, (void *)(cdata->key_virt +
++ cdata->keylen), 4, FIFOLD_CLASS_CLASS1 |
++ FIFOLD_TYPE_IV);
++ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 |
++ FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1);
++ }
++
++ append_math_sub_imm_u32(desc, VARSEQINLEN, REG3, IMM, ivsize);
+ append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ);
+
+ /* Read assoc data */
+@@ -785,7 +1321,7 @@ void cnstr_shdsc_rfc4106_encap(u32 * con
+ FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1);
+
+ /* Skip IV */
+- append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP);
++ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_SKIP);
+
+ /* Will read cryptlen bytes */
+ append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ);
+@@ -824,10 +1360,13 @@ EXPORT_SYMBOL(cnstr_shdsc_rfc4106_encap)
+ * @desc: pointer to buffer used for descriptor construction
+ * @cdata: pointer to block cipher transform definitions
+ * Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM.
++ * @ivsize: initialization vector size
+ * @icvsize: integrity check value (ICV) size (truncated or full)
++ * @is_qi: true when called from caam/qi
+ */
+ void cnstr_shdsc_rfc4106_decap(u32 * const desc, struct alginfo *cdata,
+- unsigned int icvsize)
++ unsigned int ivsize, unsigned int icvsize,
++ const bool is_qi)
+ {
+ u32 *key_jump_cmd;
+
+@@ -849,7 +1388,29 @@ void cnstr_shdsc_rfc4106_decap(u32 * con
+ append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL |
+ OP_ALG_DECRYPT | OP_ALG_ICV_ON);
+
+- append_math_sub_imm_u32(desc, VARSEQINLEN, REG3, IMM, 8);
++ if (is_qi) {
++ u32 *wait_load_cmd;
++
++ /* REG3 = assoclen */
++ append_seq_load(desc, 4, LDST_CLASS_DECO |
++ LDST_SRCDST_WORD_DECO_MATH3 |
++ (4 << LDST_OFFSET_SHIFT));
++
++ wait_load_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
++ JUMP_COND_CALM | JUMP_COND_NCP |
++ JUMP_COND_NOP | JUMP_COND_NIP |
++ JUMP_COND_NIFP);
++ set_jump_tgt_here(desc, wait_load_cmd);
++
++ /* Read salt and IV */
++ append_fifo_load_as_imm(desc, (void *)(cdata->key_virt +
++ cdata->keylen), 4, FIFOLD_CLASS_CLASS1 |
++ FIFOLD_TYPE_IV);
++ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 |
++ FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1);
++ }
++
++ append_math_sub_imm_u32(desc, VARSEQINLEN, REG3, IMM, ivsize);
+ append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ);
+
+ /* Read assoc data */
+@@ -857,7 +1418,7 @@ void cnstr_shdsc_rfc4106_decap(u32 * con
+ FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1);
+
+ /* Skip IV */
+- append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP);
++ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_SKIP);
+
+ /* Will read cryptlen bytes */
+ append_math_sub(desc, VARSEQINLEN, SEQOUTLEN, REG3, CAAM_CMD_SZ);
+@@ -896,10 +1457,13 @@ EXPORT_SYMBOL(cnstr_shdsc_rfc4106_decap)
+ * @desc: pointer to buffer used for descriptor construction
+ * @cdata: pointer to block cipher transform definitions
+ * Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM.
++ * @ivsize: initialization vector size
+ * @icvsize: integrity check value (ICV) size (truncated or full)
++ * @is_qi: true when called from caam/qi
+ */
+ void cnstr_shdsc_rfc4543_encap(u32 * const desc, struct alginfo *cdata,
+- unsigned int icvsize)
++ unsigned int ivsize, unsigned int icvsize,
++ const bool is_qi)
+ {
+ u32 *key_jump_cmd, *read_move_cmd, *write_move_cmd;
+
+@@ -920,6 +1484,18 @@ void cnstr_shdsc_rfc4543_encap(u32 * con
+ append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL |
+ OP_ALG_ENCRYPT);
+
++ if (is_qi) {
++ /* assoclen is not needed, skip it */
++ append_seq_fifo_load(desc, 4, FIFOLD_CLASS_SKIP);
++
++ /* Read salt and IV */
++ append_fifo_load_as_imm(desc, (void *)(cdata->key_virt +
++ cdata->keylen), 4, FIFOLD_CLASS_CLASS1 |
++ FIFOLD_TYPE_IV);
++ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 |
++ FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1);
++ }
++
+ /* assoclen + cryptlen = seqinlen */
+ append_math_sub(desc, REG3, SEQINLEN, REG0, CAAM_CMD_SZ);
+
+@@ -966,10 +1542,13 @@ EXPORT_SYMBOL(cnstr_shdsc_rfc4543_encap)
+ * @desc: pointer to buffer used for descriptor construction
+ * @cdata: pointer to block cipher transform definitions
+ * Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM.
++ * @ivsize: initialization vector size
+ * @icvsize: integrity check value (ICV) size (truncated or full)
++ * @is_qi: true when called from caam/qi
+ */
+ void cnstr_shdsc_rfc4543_decap(u32 * const desc, struct alginfo *cdata,
+- unsigned int icvsize)
++ unsigned int ivsize, unsigned int icvsize,
++ const bool is_qi)
+ {
+ u32 *key_jump_cmd, *read_move_cmd, *write_move_cmd;
+
+@@ -990,6 +1569,18 @@ void cnstr_shdsc_rfc4543_decap(u32 * con
+ append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL |
+ OP_ALG_DECRYPT | OP_ALG_ICV_ON);
+
++ if (is_qi) {
++ /* assoclen is not needed, skip it */
++ append_seq_fifo_load(desc, 4, FIFOLD_CLASS_SKIP);
++
++ /* Read salt and IV */
++ append_fifo_load_as_imm(desc, (void *)(cdata->key_virt +
++ cdata->keylen), 4, FIFOLD_CLASS_CLASS1 |
++ FIFOLD_TYPE_IV);
++ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 |
++ FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1);
++ }
++
+ /* assoclen + cryptlen = seqoutlen */
+ append_math_sub(desc, REG3, SEQOUTLEN, REG0, CAAM_CMD_SZ);
+
+@@ -1075,7 +1666,7 @@ void cnstr_shdsc_ablkcipher_encap(u32 *
+
+ /* Load nonce into CONTEXT1 reg */
+ if (is_rfc3686) {
+- u8 *nonce = cdata->key_virt + cdata->keylen;
++ const u8 *nonce = cdata->key_virt + cdata->keylen;
+
+ append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE,
+ LDST_CLASS_IND_CCB |
+@@ -1140,7 +1731,7 @@ void cnstr_shdsc_ablkcipher_decap(u32 *
+
+ /* Load nonce into CONTEXT1 reg */
+ if (is_rfc3686) {
+- u8 *nonce = cdata->key_virt + cdata->keylen;
++ const u8 *nonce = cdata->key_virt + cdata->keylen;
+
+ append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE,
+ LDST_CLASS_IND_CCB |
+@@ -1209,7 +1800,7 @@ void cnstr_shdsc_ablkcipher_givencap(u32
+
+ /* Load Nonce into CONTEXT1 reg */
+ if (is_rfc3686) {
+- u8 *nonce = cdata->key_virt + cdata->keylen;
++ const u8 *nonce = cdata->key_virt + cdata->keylen;
+
+ append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE,
+ LDST_CLASS_IND_CCB |
+--- a/drivers/crypto/caam/caamalg_desc.h
++++ b/drivers/crypto/caam/caamalg_desc.h
+@@ -17,6 +17,9 @@
+ #define DESC_QI_AEAD_DEC_LEN (DESC_AEAD_DEC_LEN + 3 * CAAM_CMD_SZ)
+ #define DESC_QI_AEAD_GIVENC_LEN (DESC_AEAD_GIVENC_LEN + 3 * CAAM_CMD_SZ)
+
++#define DESC_TLS_BASE (4 * CAAM_CMD_SZ)
++#define DESC_TLS10_ENC_LEN (DESC_TLS_BASE + 29 * CAAM_CMD_SZ)
++
+ /* Note: Nonce is counted in cdata.keylen */
+ #define DESC_AEAD_CTR_RFC3686_LEN (4 * CAAM_CMD_SZ)
+
+@@ -27,14 +30,20 @@
+ #define DESC_GCM_BASE (3 * CAAM_CMD_SZ)
+ #define DESC_GCM_ENC_LEN (DESC_GCM_BASE + 16 * CAAM_CMD_SZ)
+ #define DESC_GCM_DEC_LEN (DESC_GCM_BASE + 12 * CAAM_CMD_SZ)
++#define DESC_QI_GCM_ENC_LEN (DESC_GCM_ENC_LEN + 6 * CAAM_CMD_SZ)
++#define DESC_QI_GCM_DEC_LEN (DESC_GCM_DEC_LEN + 3 * CAAM_CMD_SZ)
+
+ #define DESC_RFC4106_BASE (3 * CAAM_CMD_SZ)
+ #define DESC_RFC4106_ENC_LEN (DESC_RFC4106_BASE + 13 * CAAM_CMD_SZ)
+ #define DESC_RFC4106_DEC_LEN (DESC_RFC4106_BASE + 13 * CAAM_CMD_SZ)
++#define DESC_QI_RFC4106_ENC_LEN (DESC_RFC4106_ENC_LEN + 5 * CAAM_CMD_SZ)
++#define DESC_QI_RFC4106_DEC_LEN (DESC_RFC4106_DEC_LEN + 5 * CAAM_CMD_SZ)
+
+ #define DESC_RFC4543_BASE (3 * CAAM_CMD_SZ)
+ #define DESC_RFC4543_ENC_LEN (DESC_RFC4543_BASE + 11 * CAAM_CMD_SZ)
+ #define DESC_RFC4543_DEC_LEN (DESC_RFC4543_BASE + 12 * CAAM_CMD_SZ)
++#define DESC_QI_RFC4543_ENC_LEN (DESC_RFC4543_ENC_LEN + 4 * CAAM_CMD_SZ)
++#define DESC_QI_RFC4543_DEC_LEN (DESC_RFC4543_DEC_LEN + 4 * CAAM_CMD_SZ)
+
+ #define DESC_ABLKCIPHER_BASE (3 * CAAM_CMD_SZ)
+ #define DESC_ABLKCIPHER_ENC_LEN (DESC_ABLKCIPHER_BASE + \
+@@ -43,46 +52,62 @@
+ 15 * CAAM_CMD_SZ)
+
+ void cnstr_shdsc_aead_null_encap(u32 * const desc, struct alginfo *adata,
+- unsigned int icvsize);
++ unsigned int icvsize, int era);
+
+ void cnstr_shdsc_aead_null_decap(u32 * const desc, struct alginfo *adata,
+- unsigned int icvsize);
++ unsigned int icvsize, int era);
+
+ void cnstr_shdsc_aead_encap(u32 * const desc, struct alginfo *cdata,
+ struct alginfo *adata, unsigned int ivsize,
+ unsigned int icvsize, const bool is_rfc3686,
+ u32 *nonce, const u32 ctx1_iv_off,
+- const bool is_qi);
++ const bool is_qi, int era);
+
+ void cnstr_shdsc_aead_decap(u32 * const desc, struct alginfo *cdata,
+ struct alginfo *adata, unsigned int ivsize,
+ unsigned int icvsize, const bool geniv,
+ const bool is_rfc3686, u32 *nonce,
+- const u32 ctx1_iv_off, const bool is_qi);
++ const u32 ctx1_iv_off, const bool is_qi, int era);
+
+ void cnstr_shdsc_aead_givencap(u32 * const desc, struct alginfo *cdata,
+ struct alginfo *adata, unsigned int ivsize,
+ unsigned int icvsize, const bool is_rfc3686,
+ u32 *nonce, const u32 ctx1_iv_off,
+- const bool is_qi);
++ const bool is_qi, int era);
++
++void cnstr_shdsc_tls_encap(u32 *const desc, struct alginfo *cdata,
++ struct alginfo *adata, unsigned int assoclen,
++ unsigned int ivsize, unsigned int authsize,
++ unsigned int blocksize, int era);
++
++void cnstr_shdsc_tls_decap(u32 *const desc, struct alginfo *cdata,
++ struct alginfo *adata, unsigned int assoclen,
++ unsigned int ivsize, unsigned int authsize,
++ unsigned int blocksize, int era);
+
+ void cnstr_shdsc_gcm_encap(u32 * const desc, struct alginfo *cdata,
+- unsigned int icvsize);
++ unsigned int ivsize, unsigned int icvsize,
++ const bool is_qi);
+
+ void cnstr_shdsc_gcm_decap(u32 * const desc, struct alginfo *cdata,
+- unsigned int icvsize);
++ unsigned int ivsize, unsigned int icvsize,
++ const bool is_qi);
+
+ void cnstr_shdsc_rfc4106_encap(u32 * const desc, struct alginfo *cdata,
+- unsigned int icvsize);
++ unsigned int ivsize, unsigned int icvsize,
++ const bool is_qi);
+
+ void cnstr_shdsc_rfc4106_decap(u32 * const desc, struct alginfo *cdata,
+- unsigned int icvsize);
++ unsigned int ivsize, unsigned int icvsize,
++ const bool is_qi);
+
+ void cnstr_shdsc_rfc4543_encap(u32 * const desc, struct alginfo *cdata,
+- unsigned int icvsize);
++ unsigned int ivsize, unsigned int icvsize,
++ const bool is_qi);
+
+ void cnstr_shdsc_rfc4543_decap(u32 * const desc, struct alginfo *cdata,
+- unsigned int icvsize);
++ unsigned int ivsize, unsigned int icvsize,
++ const bool is_qi);
+
+ void cnstr_shdsc_ablkcipher_encap(u32 * const desc, struct alginfo *cdata,
+ unsigned int ivsize, const bool is_rfc3686,
+--- a/drivers/crypto/caam/caamalg_qi.c
++++ b/drivers/crypto/caam/caamalg_qi.c
+@@ -7,7 +7,7 @@
+ */
+
+ #include "compat.h"
+-
++#include "ctrl.h"
+ #include "regs.h"
+ #include "intern.h"
+ #include "desc_constr.h"
+@@ -53,6 +53,7 @@ struct caam_ctx {
+ u32 sh_desc_givenc[DESC_MAX_USED_LEN];
+ u8 key[CAAM_MAX_KEY_SIZE];
+ dma_addr_t key_dma;
++ enum dma_data_direction dir;
+ struct alginfo adata;
+ struct alginfo cdata;
+ unsigned int authsize;
+@@ -74,6 +75,7 @@ static int aead_set_sh_desc(struct crypt
+ const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) ==
+ OP_ALG_AAI_CTR_MOD128);
+ const bool is_rfc3686 = alg->caam.rfc3686;
++ struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctx->jrdev->parent);
+
+ if (!ctx->cdata.keylen || !ctx->authsize)
+ return 0;
+@@ -124,7 +126,7 @@ static int aead_set_sh_desc(struct crypt
+
+ cnstr_shdsc_aead_encap(ctx->sh_desc_enc, &ctx->cdata, &ctx->adata,
+ ivsize, ctx->authsize, is_rfc3686, nonce,
+- ctx1_iv_off, true);
++ ctx1_iv_off, true, ctrlpriv->era);
+
+ skip_enc:
+ /* aead_decrypt shared descriptor */
+@@ -149,7 +151,8 @@ skip_enc:
+
+ cnstr_shdsc_aead_decap(ctx->sh_desc_dec, &ctx->cdata, &ctx->adata,
+ ivsize, ctx->authsize, alg->caam.geniv,
+- is_rfc3686, nonce, ctx1_iv_off, true);
++ is_rfc3686, nonce, ctx1_iv_off, true,
++ ctrlpriv->era);
+
+ if (!alg->caam.geniv)
+ goto skip_givenc;
+@@ -176,7 +179,7 @@ skip_enc:
+
+ cnstr_shdsc_aead_givencap(ctx->sh_desc_enc, &ctx->cdata, &ctx->adata,
+ ivsize, ctx->authsize, is_rfc3686, nonce,
+- ctx1_iv_off, true);
++ ctx1_iv_off, true, ctrlpriv->era);
+
+ skip_givenc:
+ return 0;
+@@ -197,6 +200,7 @@ static int aead_setkey(struct crypto_aea
+ {
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *jrdev = ctx->jrdev;
++ struct caam_drv_private *ctrlpriv = dev_get_drvdata(jrdev->parent);
+ struct crypto_authenc_keys keys;
+ int ret = 0;
+
+@@ -211,6 +215,27 @@ static int aead_setkey(struct crypto_aea
+ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
+ #endif
+
++ /*
++ * If DKP is supported, use it in the shared descriptor to generate
++ * the split key.
++ */
++ if (ctrlpriv->era >= 6) {
++ ctx->adata.keylen = keys.authkeylen;
++ ctx->adata.keylen_pad = split_key_len(ctx->adata.algtype &
++ OP_ALG_ALGSEL_MASK);
++
++ if (ctx->adata.keylen_pad + keys.enckeylen > CAAM_MAX_KEY_SIZE)
++ goto badkey;
++
++ memcpy(ctx->key, keys.authkey, keys.authkeylen);
++ memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey,
++ keys.enckeylen);
++ dma_sync_single_for_device(jrdev, ctx->key_dma,
++ ctx->adata.keylen_pad +
++ keys.enckeylen, ctx->dir);
++ goto skip_split_key;
++ }
++
+ ret = gen_split_key(jrdev, ctx->key, &ctx->adata, keys.authkey,
+ keys.authkeylen, CAAM_MAX_KEY_SIZE -
+ keys.enckeylen);
+@@ -220,13 +245,14 @@ static int aead_setkey(struct crypto_aea
+ /* postpend encryption key to auth split key */
+ memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen);
+ dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->adata.keylen_pad +
+- keys.enckeylen, DMA_TO_DEVICE);
++ keys.enckeylen, ctx->dir);
+ #ifdef DEBUG
+ print_hex_dump(KERN_ERR, "ctx.key@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, ctx->key,
+ ctx->adata.keylen_pad + keys.enckeylen, 1);
+ #endif
+
++skip_split_key:
+ ctx->cdata.keylen = keys.enckeylen;
+
+ ret = aead_set_sh_desc(aead);
+@@ -258,6 +284,468 @@ badkey:
+ return -EINVAL;
+ }
+
++static int tls_set_sh_desc(struct crypto_aead *tls)
++{
++ struct caam_ctx *ctx = crypto_aead_ctx(tls);
++ unsigned int ivsize = crypto_aead_ivsize(tls);
++ unsigned int blocksize = crypto_aead_blocksize(tls);
++ unsigned int assoclen = 13; /* always 13 bytes for TLS */
++ unsigned int data_len[2];
++ u32 inl_mask;
++ struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctx->jrdev->parent);
++
++ if (!ctx->cdata.keylen || !ctx->authsize)
++ return 0;
++
++ /*
++ * TLS 1.0 encrypt shared descriptor
++ * Job Descriptor and Shared Descriptor
++ * must fit into the 64-word Descriptor h/w Buffer
++ */
++ data_len[0] = ctx->adata.keylen_pad;
++ data_len[1] = ctx->cdata.keylen;
++
++ if (desc_inline_query(DESC_TLS10_ENC_LEN, DESC_JOB_IO_LEN, data_len,
++ &inl_mask, ARRAY_SIZE(data_len)) < 0)
++ return -EINVAL;
++
++ if (inl_mask & 1)
++ ctx->adata.key_virt = ctx->key;
++ else
++ ctx->adata.key_dma = ctx->key_dma;
++
++ if (inl_mask & 2)
++ ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad;
++ else
++ ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad;
++
++ ctx->adata.key_inline = !!(inl_mask & 1);
++ ctx->cdata.key_inline = !!(inl_mask & 2);
++
++ cnstr_shdsc_tls_encap(ctx->sh_desc_enc, &ctx->cdata, &ctx->adata,
++ assoclen, ivsize, ctx->authsize, blocksize,
++ ctrlpriv->era);
++
++ /*
++ * TLS 1.0 decrypt shared descriptor
++ * Keys do not fit inline, regardless of algorithms used
++ */
++ ctx->adata.key_inline = false;
++ ctx->adata.key_dma = ctx->key_dma;
++ ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad;
++
++ cnstr_shdsc_tls_decap(ctx->sh_desc_dec, &ctx->cdata, &ctx->adata,
++ assoclen, ivsize, ctx->authsize, blocksize,
++ ctrlpriv->era);
++
++ return 0;
++}
++
++static int tls_setauthsize(struct crypto_aead *tls, unsigned int authsize)
++{
++ struct caam_ctx *ctx = crypto_aead_ctx(tls);
++
++ ctx->authsize = authsize;
++ tls_set_sh_desc(tls);
++
++ return 0;
++}
++
++static int tls_setkey(struct crypto_aead *tls, const u8 *key,
++ unsigned int keylen)
++{
++ struct caam_ctx *ctx = crypto_aead_ctx(tls);
++ struct device *jrdev = ctx->jrdev;
++ struct caam_drv_private *ctrlpriv = dev_get_drvdata(jrdev->parent);
++ struct crypto_authenc_keys keys;
++ int ret = 0;
++
++ if (crypto_authenc_extractkeys(&keys, key, keylen) != 0)
++ goto badkey;
++
++#ifdef DEBUG
++ dev_err(jrdev, "keylen %d enckeylen %d authkeylen %d\n",
++ keys.authkeylen + keys.enckeylen, keys.enckeylen,
++ keys.authkeylen);
++ print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
++#endif
++
++ /*
++ * If DKP is supported, use it in the shared descriptor to generate
++ * the split key.
++ */
++ if (ctrlpriv->era >= 6) {
++ ctx->adata.keylen = keys.authkeylen;
++ ctx->adata.keylen_pad = split_key_len(ctx->adata.algtype &
++ OP_ALG_ALGSEL_MASK);
++
++ if (ctx->adata.keylen_pad + keys.enckeylen > CAAM_MAX_KEY_SIZE)
++ goto badkey;
++
++ memcpy(ctx->key, keys.authkey, keys.authkeylen);
++ memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey,
++ keys.enckeylen);
++ dma_sync_single_for_device(jrdev, ctx->key_dma,
++ ctx->adata.keylen_pad +
++ keys.enckeylen, ctx->dir);
++ goto skip_split_key;
++ }
++
++ ret = gen_split_key(jrdev, ctx->key, &ctx->adata, keys.authkey,
++ keys.authkeylen, CAAM_MAX_KEY_SIZE -
++ keys.enckeylen);
++ if (ret)
++ goto badkey;
++
++ /* postpend encryption key to auth split key */
++ memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen);
++ dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->adata.keylen_pad +
++ keys.enckeylen, ctx->dir);
++
++#ifdef DEBUG
++ dev_err(jrdev, "split keylen %d split keylen padded %d\n",
++ ctx->adata.keylen, ctx->adata.keylen_pad);
++ print_hex_dump(KERN_ERR, "ctx.key@" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, ctx->key,
++ ctx->adata.keylen_pad + keys.enckeylen, 1);
++#endif
++
++skip_split_key:
++ ctx->cdata.keylen = keys.enckeylen;
++
++ ret = tls_set_sh_desc(tls);
++ if (ret)
++ goto badkey;
++
++ /* Now update the driver contexts with the new shared descriptor */
++ if (ctx->drv_ctx[ENCRYPT]) {
++ ret = caam_drv_ctx_update(ctx->drv_ctx[ENCRYPT],
++ ctx->sh_desc_enc);
++ if (ret) {
++ dev_err(jrdev, "driver enc context update failed\n");
++ goto badkey;
++ }
++ }
++
++ if (ctx->drv_ctx[DECRYPT]) {
++ ret = caam_drv_ctx_update(ctx->drv_ctx[DECRYPT],
++ ctx->sh_desc_dec);
++ if (ret) {
++ dev_err(jrdev, "driver dec context update failed\n");
++ goto badkey;
++ }
++ }
++
++ return ret;
++badkey:
++ crypto_aead_set_flags(tls, CRYPTO_TFM_RES_BAD_KEY_LEN);
++ return -EINVAL;
++}
++
++static int gcm_set_sh_desc(struct crypto_aead *aead)
++{
++ struct caam_ctx *ctx = crypto_aead_ctx(aead);
++ unsigned int ivsize = crypto_aead_ivsize(aead);
++ int rem_bytes = CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN -
++ ctx->cdata.keylen;
++
++ if (!ctx->cdata.keylen || !ctx->authsize)
++ return 0;
++
++ /*
++ * Job Descriptor and Shared Descriptor
++ * must fit into the 64-word Descriptor h/w Buffer
++ */
++ if (rem_bytes >= DESC_QI_GCM_ENC_LEN) {
++ ctx->cdata.key_inline = true;
++ ctx->cdata.key_virt = ctx->key;
++ } else {
++ ctx->cdata.key_inline = false;
++ ctx->cdata.key_dma = ctx->key_dma;
++ }
++
++ cnstr_shdsc_gcm_encap(ctx->sh_desc_enc, &ctx->cdata, ivsize,
++ ctx->authsize, true);
++
++ /*
++ * Job Descriptor and Shared Descriptor
++ * must fit into the 64-word Descriptor h/w Buffer
++ */
++ if (rem_bytes >= DESC_QI_GCM_DEC_LEN) {
++ ctx->cdata.key_inline = true;
++ ctx->cdata.key_virt = ctx->key;
++ } else {
++ ctx->cdata.key_inline = false;
++ ctx->cdata.key_dma = ctx->key_dma;
++ }
++
++ cnstr_shdsc_gcm_decap(ctx->sh_desc_dec, &ctx->cdata, ivsize,
++ ctx->authsize, true);
++
++ return 0;
++}
++
++static int gcm_setauthsize(struct crypto_aead *authenc, unsigned int authsize)
++{
++ struct caam_ctx *ctx = crypto_aead_ctx(authenc);
++
++ ctx->authsize = authsize;
++ gcm_set_sh_desc(authenc);
++
++ return 0;
++}
++
++static int gcm_setkey(struct crypto_aead *aead,
++ const u8 *key, unsigned int keylen)
++{
++ struct caam_ctx *ctx = crypto_aead_ctx(aead);
++ struct device *jrdev = ctx->jrdev;
++ int ret;
++
++#ifdef DEBUG
++ print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
++#endif
++
++ memcpy(ctx->key, key, keylen);
++ dma_sync_single_for_device(jrdev, ctx->key_dma, keylen, ctx->dir);
++ ctx->cdata.keylen = keylen;
++
++ ret = gcm_set_sh_desc(aead);
++ if (ret)
++ return ret;
++
++ /* Now update the driver contexts with the new shared descriptor */
++ if (ctx->drv_ctx[ENCRYPT]) {
++ ret = caam_drv_ctx_update(ctx->drv_ctx[ENCRYPT],
++ ctx->sh_desc_enc);
++ if (ret) {
++ dev_err(jrdev, "driver enc context update failed\n");
++ return ret;
++ }
++ }
++
++ if (ctx->drv_ctx[DECRYPT]) {
++ ret = caam_drv_ctx_update(ctx->drv_ctx[DECRYPT],
++ ctx->sh_desc_dec);
++ if (ret) {
++ dev_err(jrdev, "driver dec context update failed\n");
++ return ret;
++ }
++ }
++
++ return 0;
++}
++
++static int rfc4106_set_sh_desc(struct crypto_aead *aead)
++{
++ struct caam_ctx *ctx = crypto_aead_ctx(aead);
++ unsigned int ivsize = crypto_aead_ivsize(aead);
++ int rem_bytes = CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN -
++ ctx->cdata.keylen;
++
++ if (!ctx->cdata.keylen || !ctx->authsize)
++ return 0;
++
++ ctx->cdata.key_virt = ctx->key;
++
++ /*
++ * Job Descriptor and Shared Descriptor
++ * must fit into the 64-word Descriptor h/w Buffer
++ */
++ if (rem_bytes >= DESC_QI_RFC4106_ENC_LEN) {
++ ctx->cdata.key_inline = true;
++ } else {
++ ctx->cdata.key_inline = false;
++ ctx->cdata.key_dma = ctx->key_dma;
++ }
++
++ cnstr_shdsc_rfc4106_encap(ctx->sh_desc_enc, &ctx->cdata, ivsize,
++ ctx->authsize, true);
++
++ /*
++ * Job Descriptor and Shared Descriptor
++ * must fit into the 64-word Descriptor h/w Buffer
++ */
++ if (rem_bytes >= DESC_QI_RFC4106_DEC_LEN) {
++ ctx->cdata.key_inline = true;
++ } else {
++ ctx->cdata.key_inline = false;
++ ctx->cdata.key_dma = ctx->key_dma;
++ }
++
++ cnstr_shdsc_rfc4106_decap(ctx->sh_desc_dec, &ctx->cdata, ivsize,
++ ctx->authsize, true);
++
++ return 0;
++}
++
++static int rfc4106_setauthsize(struct crypto_aead *authenc,
++ unsigned int authsize)
++{
++ struct caam_ctx *ctx = crypto_aead_ctx(authenc);
++
++ ctx->authsize = authsize;
++ rfc4106_set_sh_desc(authenc);
++
++ return 0;
++}
++
++static int rfc4106_setkey(struct crypto_aead *aead,
++ const u8 *key, unsigned int keylen)
++{
++ struct caam_ctx *ctx = crypto_aead_ctx(aead);
++ struct device *jrdev = ctx->jrdev;
++ int ret;
++
++ if (keylen < 4)
++ return -EINVAL;
++
++#ifdef DEBUG
++ print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
++#endif
++
++ memcpy(ctx->key, key, keylen);
++ /*
++ * The last four bytes of the key material are used as the salt value
++ * in the nonce. Update the AES key length.
++ */
++ ctx->cdata.keylen = keylen - 4;
++ dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->cdata.keylen,
++ ctx->dir);
++
++ ret = rfc4106_set_sh_desc(aead);
++ if (ret)
++ return ret;
++
++ /* Now update the driver contexts with the new shared descriptor */
++ if (ctx->drv_ctx[ENCRYPT]) {
++ ret = caam_drv_ctx_update(ctx->drv_ctx[ENCRYPT],
++ ctx->sh_desc_enc);
++ if (ret) {
++ dev_err(jrdev, "driver enc context update failed\n");
++ return ret;
++ }
++ }
++
++ if (ctx->drv_ctx[DECRYPT]) {
++ ret = caam_drv_ctx_update(ctx->drv_ctx[DECRYPT],
++ ctx->sh_desc_dec);
++ if (ret) {
++ dev_err(jrdev, "driver dec context update failed\n");
++ return ret;
++ }
++ }
++
++ return 0;
++}
++
++static int rfc4543_set_sh_desc(struct crypto_aead *aead)
++{
++ struct caam_ctx *ctx = crypto_aead_ctx(aead);
++ unsigned int ivsize = crypto_aead_ivsize(aead);
++ int rem_bytes = CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN -
++ ctx->cdata.keylen;
++
++ if (!ctx->cdata.keylen || !ctx->authsize)
++ return 0;
++
++ ctx->cdata.key_virt = ctx->key;
++
++ /*
++ * Job Descriptor and Shared Descriptor
++ * must fit into the 64-word Descriptor h/w Buffer
++ */
++ if (rem_bytes >= DESC_QI_RFC4543_ENC_LEN) {
++ ctx->cdata.key_inline = true;
++ } else {
++ ctx->cdata.key_inline = false;
++ ctx->cdata.key_dma = ctx->key_dma;
++ }
++
++ cnstr_shdsc_rfc4543_encap(ctx->sh_desc_enc, &ctx->cdata, ivsize,
++ ctx->authsize, true);
++
++ /*
++ * Job Descriptor and Shared Descriptor
++ * must fit into the 64-word Descriptor h/w Buffer
++ */
++ if (rem_bytes >= DESC_QI_RFC4543_DEC_LEN) {
++ ctx->cdata.key_inline = true;
++ } else {
++ ctx->cdata.key_inline = false;
++ ctx->cdata.key_dma = ctx->key_dma;
++ }
++
++ cnstr_shdsc_rfc4543_decap(ctx->sh_desc_dec, &ctx->cdata, ivsize,
++ ctx->authsize, true);
++
++ return 0;
++}
++
++static int rfc4543_setauthsize(struct crypto_aead *authenc,
++ unsigned int authsize)
++{
++ struct caam_ctx *ctx = crypto_aead_ctx(authenc);
++
++ ctx->authsize = authsize;
++ rfc4543_set_sh_desc(authenc);
++
++ return 0;
++}
++
++static int rfc4543_setkey(struct crypto_aead *aead,
++ const u8 *key, unsigned int keylen)
++{
++ struct caam_ctx *ctx = crypto_aead_ctx(aead);
++ struct device *jrdev = ctx->jrdev;
++ int ret;
++
++ if (keylen < 4)
++ return -EINVAL;
++
++#ifdef DEBUG
++ print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
++#endif
++
++ memcpy(ctx->key, key, keylen);
++ /*
++ * The last four bytes of the key material are used as the salt value
++ * in the nonce. Update the AES key length.
++ */
++ ctx->cdata.keylen = keylen - 4;
++ dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->cdata.keylen,
++ ctx->dir);
++
++ ret = rfc4543_set_sh_desc(aead);
++ if (ret)
++ return ret;
++
++ /* Now update the driver contexts with the new shared descriptor */
++ if (ctx->drv_ctx[ENCRYPT]) {
++ ret = caam_drv_ctx_update(ctx->drv_ctx[ENCRYPT],
++ ctx->sh_desc_enc);
++ if (ret) {
++ dev_err(jrdev, "driver enc context update failed\n");
++ return ret;
++ }
++ }
++
++ if (ctx->drv_ctx[DECRYPT]) {
++ ret = caam_drv_ctx_update(ctx->drv_ctx[DECRYPT],
++ ctx->sh_desc_dec);
++ if (ret) {
++ dev_err(jrdev, "driver dec context update failed\n");
++ return ret;
++ }
++ }
++
++ return 0;
++}
++
+ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
+ const u8 *key, unsigned int keylen)
+ {
+@@ -414,6 +902,29 @@ struct aead_edesc {
+ };
+
+ /*
++ * tls_edesc - s/w-extended tls descriptor
++ * @src_nents: number of segments in input scatterlist
++ * @dst_nents: number of segments in output scatterlist
++ * @iv_dma: dma address of iv for checking continuity and link table
++ * @qm_sg_bytes: length of dma mapped h/w link table
++ * @tmp: array of scatterlists used by 'scatterwalk_ffwd'
++ * @qm_sg_dma: bus physical mapped address of h/w link table
++ * @drv_req: driver-specific request structure
++ * @sgt: the h/w link table, followed by IV
++ */
++struct tls_edesc {
++ int src_nents;
++ int dst_nents;
++ dma_addr_t iv_dma;
++ int qm_sg_bytes;
++ dma_addr_t qm_sg_dma;
++ struct scatterlist tmp[2];
++ struct scatterlist *dst;
++ struct caam_drv_req drv_req;
++ struct qm_sg_entry sgt[0];
++};
++
++/*
+ * ablkcipher_edesc - s/w-extended ablkcipher descriptor
+ * @src_nents: number of segments in input scatterlist
+ * @dst_nents: number of segments in output scatterlist
+@@ -508,6 +1019,19 @@ static void aead_unmap(struct device *de
+ dma_unmap_single(dev, edesc->assoclen_dma, 4, DMA_TO_DEVICE);
+ }
+
++static void tls_unmap(struct device *dev,
++ struct tls_edesc *edesc,
++ struct aead_request *req)
++{
++ struct crypto_aead *aead = crypto_aead_reqtfm(req);
++ int ivsize = crypto_aead_ivsize(aead);
++
++ caam_unmap(dev, req->src, edesc->dst, edesc->src_nents,
++ edesc->dst_nents, edesc->iv_dma, ivsize,
++ edesc->drv_req.drv_ctx->op_type, edesc->qm_sg_dma,
++ edesc->qm_sg_bytes);
++}
++
+ static void ablkcipher_unmap(struct device *dev,
+ struct ablkcipher_edesc *edesc,
+ struct ablkcipher_request *req)
+@@ -532,8 +1056,18 @@ static void aead_done(struct caam_drv_re
+ qidev = caam_ctx->qidev;
+
+ if (unlikely(status)) {
++ u32 ssrc = status & JRSTA_SSRC_MASK;
++ u8 err_id = status & JRSTA_CCBERR_ERRID_MASK;
++
+ caam_jr_strstatus(qidev, status);
+- ecode = -EIO;
++ /*
++ * verify hw auth check passed else return -EBADMSG
++ */
++ if (ssrc == JRSTA_SSRC_CCB_ERROR &&
++ err_id == JRSTA_CCBERR_ERRID_ICVCHK)
++ ecode = -EBADMSG;
++ else
++ ecode = -EIO;
+ }
+
+ edesc = container_of(drv_req, typeof(*edesc), drv_req);
+@@ -785,6 +1319,260 @@ static int aead_decrypt(struct aead_requ
+ return aead_crypt(req, false);
+ }
+
++static int ipsec_gcm_encrypt(struct aead_request *req)
++{
++ if (req->assoclen < 8)
++ return -EINVAL;
++
++ return aead_crypt(req, true);
++}
++
++static int ipsec_gcm_decrypt(struct aead_request *req)
++{
++ if (req->assoclen < 8)
++ return -EINVAL;
++
++ return aead_crypt(req, false);
++}
++
++static void tls_done(struct caam_drv_req *drv_req, u32 status)
++{
++ struct device *qidev;
++ struct tls_edesc *edesc;
++ struct aead_request *aead_req = drv_req->app_ctx;
++ struct crypto_aead *aead = crypto_aead_reqtfm(aead_req);
++ struct caam_ctx *caam_ctx = crypto_aead_ctx(aead);
++ int ecode = 0;
++
++ qidev = caam_ctx->qidev;
++
++ if (unlikely(status)) {
++ caam_jr_strstatus(qidev, status);
++ ecode = -EIO;
++ }
++
++ edesc = container_of(drv_req, typeof(*edesc), drv_req);
++ tls_unmap(qidev, edesc, aead_req);
++
++ aead_request_complete(aead_req, ecode);
++ qi_cache_free(edesc);
++}
++
++/*
++ * allocate and map the tls extended descriptor
++ */
++static struct tls_edesc *tls_edesc_alloc(struct aead_request *req, bool encrypt)
++{
++ struct crypto_aead *aead = crypto_aead_reqtfm(req);
++ struct caam_ctx *ctx = crypto_aead_ctx(aead);
++ unsigned int blocksize = crypto_aead_blocksize(aead);
++ unsigned int padsize, authsize;
++ struct caam_aead_alg *alg = container_of(crypto_aead_alg(aead),
++ typeof(*alg), aead);
++ struct device *qidev = ctx->qidev;
++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
++ GFP_KERNEL : GFP_ATOMIC;
++ int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0;
++ struct tls_edesc *edesc;
++ dma_addr_t qm_sg_dma, iv_dma = 0;
++ int ivsize = 0;
++ u8 *iv;
++ int qm_sg_index, qm_sg_ents = 0, qm_sg_bytes;
++ int in_len, out_len;
++ struct qm_sg_entry *sg_table, *fd_sgt;
++ struct caam_drv_ctx *drv_ctx;
++ enum optype op_type = encrypt ? ENCRYPT : DECRYPT;
++ struct scatterlist *dst;
++
++ if (encrypt) {
++ padsize = blocksize - ((req->cryptlen + ctx->authsize) %
++ blocksize);
++ authsize = ctx->authsize + padsize;
++ } else {
++ authsize = ctx->authsize;
++ }
++
++ drv_ctx = get_drv_ctx(ctx, op_type);
++ if (unlikely(IS_ERR_OR_NULL(drv_ctx)))
++ return (struct tls_edesc *)drv_ctx;
++
++ /* allocate space for base edesc, link tables and IV */
++ edesc = qi_cache_alloc(GFP_DMA | flags);
++ if (unlikely(!edesc)) {
++ dev_err(qidev, "could not allocate extended descriptor\n");
++ return ERR_PTR(-ENOMEM);
++ }
++
++ if (likely(req->src == req->dst)) {
++ src_nents = sg_nents_for_len(req->src, req->assoclen +
++ req->cryptlen +
++ (encrypt ? authsize : 0));
++ if (unlikely(src_nents < 0)) {
++ dev_err(qidev, "Insufficient bytes (%d) in src S/G\n",
++ req->assoclen + req->cryptlen +
++ (encrypt ? authsize : 0));
++ qi_cache_free(edesc);
++ return ERR_PTR(src_nents);
++ }
++
++ mapped_src_nents = dma_map_sg(qidev, req->src, src_nents,
++ DMA_BIDIRECTIONAL);
++ if (unlikely(!mapped_src_nents)) {
++ dev_err(qidev, "unable to map source\n");
++ qi_cache_free(edesc);
++ return ERR_PTR(-ENOMEM);
++ }
++ dst = req->dst;
++ } else {
++ src_nents = sg_nents_for_len(req->src, req->assoclen +
++ req->cryptlen);
++ if (unlikely(src_nents < 0)) {
++ dev_err(qidev, "Insufficient bytes (%d) in src S/G\n",
++ req->assoclen + req->cryptlen);
++ qi_cache_free(edesc);
++ return ERR_PTR(src_nents);
++ }
++
++ dst = scatterwalk_ffwd(edesc->tmp, req->dst, req->assoclen);
++ dst_nents = sg_nents_for_len(dst, req->cryptlen +
++ (encrypt ? authsize : 0));
++ if (unlikely(dst_nents < 0)) {
++ dev_err(qidev, "Insufficient bytes (%d) in dst S/G\n",
++ req->cryptlen +
++ (encrypt ? authsize : 0));
++ qi_cache_free(edesc);
++ return ERR_PTR(dst_nents);
++ }
++
++ if (src_nents) {
++ mapped_src_nents = dma_map_sg(qidev, req->src,
++ src_nents, DMA_TO_DEVICE);
++ if (unlikely(!mapped_src_nents)) {
++ dev_err(qidev, "unable to map source\n");
++ qi_cache_free(edesc);
++ return ERR_PTR(-ENOMEM);
++ }
++ } else {
++ mapped_src_nents = 0;
++ }
++
++ mapped_dst_nents = dma_map_sg(qidev, dst, dst_nents,
++ DMA_FROM_DEVICE);
++ if (unlikely(!mapped_dst_nents)) {
++ dev_err(qidev, "unable to map destination\n");
++ dma_unmap_sg(qidev, req->src, src_nents, DMA_TO_DEVICE);
++ qi_cache_free(edesc);
++ return ERR_PTR(-ENOMEM);
++ }
++ }
++
++ /*
++ * Create S/G table: IV, src, dst.
++ * Input is not contiguous.
++ */
++ qm_sg_ents = 1 + mapped_src_nents +
++ (mapped_dst_nents > 1 ? mapped_dst_nents : 0);
++ sg_table = &edesc->sgt[0];
++ qm_sg_bytes = qm_sg_ents * sizeof(*sg_table);
++
++ ivsize = crypto_aead_ivsize(aead);
++ iv = (u8 *)(sg_table + qm_sg_ents);
++ /* Make sure IV is located in a DMAable area */
++ memcpy(iv, req->iv, ivsize);
++ iv_dma = dma_map_single(qidev, iv, ivsize, DMA_TO_DEVICE);
++ if (dma_mapping_error(qidev, iv_dma)) {
++ dev_err(qidev, "unable to map IV\n");
++ caam_unmap(qidev, req->src, dst, src_nents, dst_nents, 0, 0, 0,
++ 0, 0);
++ qi_cache_free(edesc);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ edesc->src_nents = src_nents;
++ edesc->dst_nents = dst_nents;
++ edesc->dst = dst;
++ edesc->iv_dma = iv_dma;
++ edesc->drv_req.app_ctx = req;
++ edesc->drv_req.cbk = tls_done;
++ edesc->drv_req.drv_ctx = drv_ctx;
++
++ dma_to_qm_sg_one(sg_table, iv_dma, ivsize, 0);
++ qm_sg_index = 1;
++
++ sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + qm_sg_index, 0);
++ qm_sg_index += mapped_src_nents;
++
++ if (mapped_dst_nents > 1)
++ sg_to_qm_sg_last(dst, mapped_dst_nents, sg_table +
++ qm_sg_index, 0);
++
++ qm_sg_dma = dma_map_single(qidev, sg_table, qm_sg_bytes, DMA_TO_DEVICE);
++ if (dma_mapping_error(qidev, qm_sg_dma)) {
++ dev_err(qidev, "unable to map S/G table\n");
++ caam_unmap(qidev, req->src, dst, src_nents, dst_nents, iv_dma,
++ ivsize, op_type, 0, 0);
++ qi_cache_free(edesc);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ edesc->qm_sg_dma = qm_sg_dma;
++ edesc->qm_sg_bytes = qm_sg_bytes;
++
++ out_len = req->cryptlen + (encrypt ? authsize : 0);
++ in_len = ivsize + req->assoclen + req->cryptlen;
++
++ fd_sgt = &edesc->drv_req.fd_sgt[0];
++
++ dma_to_qm_sg_one_last_ext(&fd_sgt[1], qm_sg_dma, in_len, 0);
++
++ if (req->dst == req->src)
++ dma_to_qm_sg_one_ext(&fd_sgt[0], qm_sg_dma +
++ (sg_nents_for_len(req->src, req->assoclen) +
++ 1) * sizeof(*sg_table), out_len, 0);
++ else if (mapped_dst_nents == 1)
++ dma_to_qm_sg_one(&fd_sgt[0], sg_dma_address(dst), out_len, 0);
++ else
++ dma_to_qm_sg_one_ext(&fd_sgt[0], qm_sg_dma + sizeof(*sg_table) *
++ qm_sg_index, out_len, 0);
++
++ return edesc;
++}
++
++static int tls_crypt(struct aead_request *req, bool encrypt)
++{
++ struct tls_edesc *edesc;
++ struct crypto_aead *aead = crypto_aead_reqtfm(req);
++ struct caam_ctx *ctx = crypto_aead_ctx(aead);
++ int ret;
++
++ if (unlikely(caam_congested))
++ return -EAGAIN;
++
++ edesc = tls_edesc_alloc(req, encrypt);
++ if (IS_ERR_OR_NULL(edesc))
++ return PTR_ERR(edesc);
++
++ ret = caam_qi_enqueue(ctx->qidev, &edesc->drv_req);
++ if (!ret) {
++ ret = -EINPROGRESS;
++ } else {
++ tls_unmap(ctx->qidev, edesc, req);
++ qi_cache_free(edesc);
++ }
++
++ return ret;
++}
++
++static int tls_encrypt(struct aead_request *req)
++{
++ return tls_crypt(req, true);
++}
++
++static int tls_decrypt(struct aead_request *req)
++{
++ return tls_crypt(req, false);
++}
++
+ static void ablkcipher_done(struct caam_drv_req *drv_req, u32 status)
+ {
+ struct ablkcipher_edesc *edesc;
+@@ -1308,6 +2096,61 @@ static struct caam_alg_template driver_a
+ };
+
+ static struct caam_aead_alg driver_aeads[] = {
++ {
++ .aead = {
++ .base = {
++ .cra_name = "rfc4106(gcm(aes))",
++ .cra_driver_name = "rfc4106-gcm-aes-caam-qi",
++ .cra_blocksize = 1,
++ },
++ .setkey = rfc4106_setkey,
++ .setauthsize = rfc4106_setauthsize,
++ .encrypt = ipsec_gcm_encrypt,
++ .decrypt = ipsec_gcm_decrypt,
++ .ivsize = 8,
++ .maxauthsize = AES_BLOCK_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
++ },
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "rfc4543(gcm(aes))",
++ .cra_driver_name = "rfc4543-gcm-aes-caam-qi",
++ .cra_blocksize = 1,
++ },
++ .setkey = rfc4543_setkey,
++ .setauthsize = rfc4543_setauthsize,
++ .encrypt = ipsec_gcm_encrypt,
++ .decrypt = ipsec_gcm_decrypt,
++ .ivsize = 8,
++ .maxauthsize = AES_BLOCK_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
++ },
++ },
++ /* Galois Counter Mode */
++ {
++ .aead = {
++ .base = {
++ .cra_name = "gcm(aes)",
++ .cra_driver_name = "gcm-aes-caam-qi",
++ .cra_blocksize = 1,
++ },
++ .setkey = gcm_setkey,
++ .setauthsize = gcm_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = 12,
++ .maxauthsize = AES_BLOCK_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
++ }
++ },
+ /* single-pass ipsec_esp descriptor */
+ {
+ .aead = {
+@@ -2118,6 +2961,26 @@ static struct caam_aead_alg driver_aeads
+ .geniv = true,
+ }
+ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "tls10(hmac(sha1),cbc(aes))",
++ .cra_driver_name = "tls10-hmac-sha1-cbc-aes-caam-qi",
++ .cra_blocksize = AES_BLOCK_SIZE,
++ },
++ .setkey = tls_setkey,
++ .setauthsize = tls_setauthsize,
++ .encrypt = tls_encrypt,
++ .decrypt = tls_decrypt,
++ .ivsize = AES_BLOCK_SIZE,
++ .maxauthsize = SHA1_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA1 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ }
++ }
+ };
+
+ struct caam_crypto_alg {
+@@ -2126,9 +2989,20 @@ struct caam_crypto_alg {
+ struct caam_alg_entry caam;
+ };
+
+-static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam)
++static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam,
++ bool uses_dkp)
+ {
+ struct caam_drv_private *priv;
++ /* Digest sizes for MD5, SHA1, SHA-224, SHA-256, SHA-384, SHA-512 */
++ static const u8 digest_size[] = {
++ MD5_DIGEST_SIZE,
++ SHA1_DIGEST_SIZE,
++ SHA224_DIGEST_SIZE,
++ SHA256_DIGEST_SIZE,
++ SHA384_DIGEST_SIZE,
++ SHA512_DIGEST_SIZE
++ };
++ u8 op_id;
+
+ /*
+ * distribute tfms across job rings to ensure in-order
+@@ -2140,8 +3014,14 @@ static int caam_init_common(struct caam_
+ return PTR_ERR(ctx->jrdev);
+ }
+
++ priv = dev_get_drvdata(ctx->jrdev->parent);
++ if (priv->era >= 6 && uses_dkp)
++ ctx->dir = DMA_BIDIRECTIONAL;
++ else
++ ctx->dir = DMA_TO_DEVICE;
++
+ ctx->key_dma = dma_map_single(ctx->jrdev, ctx->key, sizeof(ctx->key),
+- DMA_TO_DEVICE);
++ ctx->dir);
+ if (dma_mapping_error(ctx->jrdev, ctx->key_dma)) {
+ dev_err(ctx->jrdev, "unable to map key\n");
+ caam_jr_free(ctx->jrdev);
+@@ -2152,7 +3032,22 @@ static int caam_init_common(struct caam_
+ ctx->cdata.algtype = OP_TYPE_CLASS1_ALG | caam->class1_alg_type;
+ ctx->adata.algtype = OP_TYPE_CLASS2_ALG | caam->class2_alg_type;
+
+- priv = dev_get_drvdata(ctx->jrdev->parent);
++ if (ctx->adata.algtype) {
++ op_id = (ctx->adata.algtype & OP_ALG_ALGSEL_SUBMASK)
++ >> OP_ALG_ALGSEL_SHIFT;
++ if (op_id < ARRAY_SIZE(digest_size)) {
++ ctx->authsize = digest_size[op_id];
++ } else {
++ dev_err(ctx->jrdev,
++ "incorrect op_id %d; must be less than %zu\n",
++ op_id, ARRAY_SIZE(digest_size));
++ caam_jr_free(ctx->jrdev);
++ return -EINVAL;
++ }
++ } else {
++ ctx->authsize = 0;
++ }
++
+ ctx->qidev = priv->qidev;
+
+ spin_lock_init(&ctx->lock);
+@@ -2170,7 +3065,7 @@ static int caam_cra_init(struct crypto_t
+ crypto_alg);
+ struct caam_ctx *ctx = crypto_tfm_ctx(tfm);
+
+- return caam_init_common(ctx, &caam_alg->caam);
++ return caam_init_common(ctx, &caam_alg->caam, false);
+ }
+
+ static int caam_aead_init(struct crypto_aead *tfm)
+@@ -2180,7 +3075,9 @@ static int caam_aead_init(struct crypto_
+ aead);
+ struct caam_ctx *ctx = crypto_aead_ctx(tfm);
+
+- return caam_init_common(ctx, &caam_alg->caam);
++ return caam_init_common(ctx, &caam_alg->caam,
++ (alg->setkey == aead_setkey) ||
++ (alg->setkey == tls_setkey));
+ }
+
+ static void caam_exit_common(struct caam_ctx *ctx)
+@@ -2189,8 +3086,7 @@ static void caam_exit_common(struct caam
+ caam_drv_ctx_rel(ctx->drv_ctx[DECRYPT]);
+ caam_drv_ctx_rel(ctx->drv_ctx[GIVENCRYPT]);
+
+- dma_unmap_single(ctx->jrdev, ctx->key_dma, sizeof(ctx->key),
+- DMA_TO_DEVICE);
++ dma_unmap_single(ctx->jrdev, ctx->key_dma, sizeof(ctx->key), ctx->dir);
+
+ caam_jr_free(ctx->jrdev);
+ }
+@@ -2315,6 +3211,11 @@ static int __init caam_qi_algapi_init(vo
+ if (!priv || !priv->qi_present)
+ return -ENODEV;
+
++ if (caam_dpaa2) {
++ dev_info(ctrldev, "caam/qi frontend driver not suitable for DPAA 2.x, aborting...\n");
++ return -ENODEV;
++ }
++
+ INIT_LIST_HEAD(&alg_list);
+
+ /*
+--- /dev/null
++++ b/drivers/crypto/caam/caamalg_qi2.c
+@@ -0,0 +1,5691 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
++/*
++ * Copyright 2015-2016 Freescale Semiconductor Inc.
++ * Copyright 2017-2018 NXP
++ */
++
++#include <linux/fsl/mc.h>
++#include "compat.h"
++#include "regs.h"
++#include "caamalg_qi2.h"
++#include "dpseci_cmd.h"
++#include "desc_constr.h"
++#include "error.h"
++#include "sg_sw_sec4.h"
++#include "sg_sw_qm2.h"
++#include "key_gen.h"
++#include "caamalg_desc.h"
++#include "caamhash_desc.h"
++#include "../../../drivers/staging/fsl-mc/include/dpaa2-io.h"
++#include "../../../drivers/staging/fsl-mc/include/dpaa2-fd.h"
++
++#define CAAM_CRA_PRIORITY 2000
++
++/* max key is sum of AES_MAX_KEY_SIZE, max split key size */
++#define CAAM_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + CTR_RFC3686_NONCE_SIZE + \
++ SHA512_DIGEST_SIZE * 2)
++
++#ifndef CONFIG_CRYPTO_DEV_FSL_CAAM
++bool caam_little_end;
++EXPORT_SYMBOL(caam_little_end);
++bool caam_imx;
++EXPORT_SYMBOL(caam_imx);
++#endif
++
++/*
++ * This is a a cache of buffers, from which the users of CAAM QI driver
++ * can allocate short buffers. It's speedier than doing kmalloc on the hotpath.
++ * NOTE: A more elegant solution would be to have some headroom in the frames
++ * being processed. This can be added by the dpaa2-eth driver. This would
++ * pose a problem for userspace application processing which cannot
++ * know of this limitation. So for now, this will work.
++ * NOTE: The memcache is SMP-safe. No need to handle spinlocks in-here
++ */
++static struct kmem_cache *qi_cache;
++
++struct caam_alg_entry {
++ struct device *dev;
++ int class1_alg_type;
++ int class2_alg_type;
++ bool rfc3686;
++ bool geniv;
++};
++
++struct caam_aead_alg {
++ struct aead_alg aead;
++ struct caam_alg_entry caam;
++ bool registered;
++};
++
++struct caam_skcipher_alg {
++ struct skcipher_alg skcipher;
++ struct caam_alg_entry caam;
++ bool registered;
++};
++
++/**
++ * caam_ctx - per-session context
++ * @flc: Flow Contexts array
++ * @key: virtual address of the key(s): [authentication key], encryption key
++ * @flc_dma: I/O virtual addresses of the Flow Contexts
++ * @key_dma: I/O virtual address of the key
++ * @dir: DMA direction for mapping key and Flow Contexts
++ * @dev: dpseci device
++ * @adata: authentication algorithm details
++ * @cdata: encryption algorithm details
++ * @authsize: authentication tag (a.k.a. ICV / MAC) size
++ */
++struct caam_ctx {
++ struct caam_flc flc[NUM_OP];
++ u8 key[CAAM_MAX_KEY_SIZE];
++ dma_addr_t flc_dma[NUM_OP];
++ dma_addr_t key_dma;
++ enum dma_data_direction dir;
++ struct device *dev;
++ struct alginfo adata;
++ struct alginfo cdata;
++ unsigned int authsize;
++};
++
++void *dpaa2_caam_iova_to_virt(struct dpaa2_caam_priv *priv,
++ dma_addr_t iova_addr)
++{
++ phys_addr_t phys_addr;
++
++ phys_addr = priv->domain ? iommu_iova_to_phys(priv->domain, iova_addr) :
++ iova_addr;
++
++ return phys_to_virt(phys_addr);
++}
++
++/*
++ * qi_cache_zalloc - Allocate buffers from CAAM-QI cache
++ *
++ * Allocate data on the hotpath. Instead of using kzalloc, one can use the
++ * services of the CAAM QI memory cache (backed by kmem_cache). The buffers
++ * will have a size of CAAM_QI_MEMCACHE_SIZE, which should be sufficient for
++ * hosting 16 SG entries.
++ *
++ * @flags - flags that would be used for the equivalent kmalloc(..) call
++ *
++ * Returns a pointer to a retrieved buffer on success or NULL on failure.
++ */
++static inline void *qi_cache_zalloc(gfp_t flags)
++{
++ return kmem_cache_zalloc(qi_cache, flags);
++}
++
++/*
++ * qi_cache_free - Frees buffers allocated from CAAM-QI cache
++ *
++ * @obj - buffer previously allocated by qi_cache_zalloc
++ *
++ * No checking is being done, the call is a passthrough call to
++ * kmem_cache_free(...)
++ */
++static inline void qi_cache_free(void *obj)
++{
++ kmem_cache_free(qi_cache, obj);
++}
++
++static struct caam_request *to_caam_req(struct crypto_async_request *areq)
++{
++ switch (crypto_tfm_alg_type(areq->tfm)) {
++ case CRYPTO_ALG_TYPE_SKCIPHER:
++ return skcipher_request_ctx(skcipher_request_cast(areq));
++ case CRYPTO_ALG_TYPE_AEAD:
++ return aead_request_ctx(container_of(areq, struct aead_request,
++ base));
++ case CRYPTO_ALG_TYPE_AHASH:
++ return ahash_request_ctx(ahash_request_cast(areq));
++ default:
++ return ERR_PTR(-EINVAL);
++ }
++}
++
++static void caam_unmap(struct device *dev, struct scatterlist *src,
++ struct scatterlist *dst, int src_nents,
++ int dst_nents, dma_addr_t iv_dma, int ivsize,
++ dma_addr_t qm_sg_dma, int qm_sg_bytes)
++{
++ if (dst != src) {
++ if (src_nents)
++ dma_unmap_sg(dev, src, src_nents, DMA_TO_DEVICE);
++ dma_unmap_sg(dev, dst, dst_nents, DMA_FROM_DEVICE);
++ } else {
++ dma_unmap_sg(dev, src, src_nents, DMA_BIDIRECTIONAL);
++ }
++
++ if (iv_dma)
++ dma_unmap_single(dev, iv_dma, ivsize, DMA_TO_DEVICE);
++
++ if (qm_sg_bytes)
++ dma_unmap_single(dev, qm_sg_dma, qm_sg_bytes, DMA_TO_DEVICE);
++}
++
++static int aead_set_sh_desc(struct crypto_aead *aead)
++{
++ struct caam_aead_alg *alg = container_of(crypto_aead_alg(aead),
++ typeof(*alg), aead);
++ struct caam_ctx *ctx = crypto_aead_ctx(aead);
++ unsigned int ivsize = crypto_aead_ivsize(aead);
++ struct device *dev = ctx->dev;
++ struct dpaa2_caam_priv *priv = dev_get_drvdata(dev);
++ struct caam_flc *flc;
++ u32 *desc;
++ u32 ctx1_iv_off = 0;
++ u32 *nonce = NULL;
++ unsigned int data_len[2];
++ u32 inl_mask;
++ const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) ==
++ OP_ALG_AAI_CTR_MOD128);
++ const bool is_rfc3686 = alg->caam.rfc3686;
++
++ if (!ctx->cdata.keylen || !ctx->authsize)
++ return 0;
++
++ /*
++ * AES-CTR needs to load IV in CONTEXT1 reg
++ * at an offset of 128bits (16bytes)
++ * CONTEXT1[255:128] = IV
++ */
++ if (ctr_mode)
++ ctx1_iv_off = 16;
++
++ /*
++ * RFC3686 specific:
++ * CONTEXT1[255:128] = {NONCE, IV, COUNTER}
++ */
++ if (is_rfc3686) {
++ ctx1_iv_off = 16 + CTR_RFC3686_NONCE_SIZE;
++ nonce = (u32 *)((void *)ctx->key + ctx->adata.keylen_pad +
++ ctx->cdata.keylen - CTR_RFC3686_NONCE_SIZE);
++ }
++
++ data_len[0] = ctx->adata.keylen_pad;
++ data_len[1] = ctx->cdata.keylen;
++
++ /* aead_encrypt shared descriptor */
++ if (desc_inline_query((alg->caam.geniv ? DESC_QI_AEAD_GIVENC_LEN :
++ DESC_QI_AEAD_ENC_LEN) +
++ (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0),
++ DESC_JOB_IO_LEN, data_len, &inl_mask,
++ ARRAY_SIZE(data_len)) < 0)
++ return -EINVAL;
++
++ if (inl_mask & 1)
++ ctx->adata.key_virt = ctx->key;
++ else
++ ctx->adata.key_dma = ctx->key_dma;
++
++ if (inl_mask & 2)
++ ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad;
++ else
++ ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad;
++
++ ctx->adata.key_inline = !!(inl_mask & 1);
++ ctx->cdata.key_inline = !!(inl_mask & 2);
++
++ flc = &ctx->flc[ENCRYPT];
++ desc = flc->sh_desc;
++
++ if (alg->caam.geniv)
++ cnstr_shdsc_aead_givencap(desc, &ctx->cdata, &ctx->adata,
++ ivsize, ctx->authsize, is_rfc3686,
++ nonce, ctx1_iv_off, true,
++ priv->sec_attr.era);
++ else
++ cnstr_shdsc_aead_encap(desc, &ctx->cdata, &ctx->adata,
++ ivsize, ctx->authsize, is_rfc3686, nonce,
++ ctx1_iv_off, true, priv->sec_attr.era);
++
++ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
++ dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT],
++ sizeof(flc->flc) + desc_bytes(desc),
++ ctx->dir);
++
++ /* aead_decrypt shared descriptor */
++ if (desc_inline_query(DESC_QI_AEAD_DEC_LEN +
++ (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0),
++ DESC_JOB_IO_LEN, data_len, &inl_mask,
++ ARRAY_SIZE(data_len)) < 0)
++ return -EINVAL;
++
++ if (inl_mask & 1)
++ ctx->adata.key_virt = ctx->key;
++ else
++ ctx->adata.key_dma = ctx->key_dma;
++
++ if (inl_mask & 2)
++ ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad;
++ else
++ ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad;
++
++ ctx->adata.key_inline = !!(inl_mask & 1);
++ ctx->cdata.key_inline = !!(inl_mask & 2);
++
++ flc = &ctx->flc[DECRYPT];
++ desc = flc->sh_desc;
++ cnstr_shdsc_aead_decap(desc, &ctx->cdata, &ctx->adata,
++ ivsize, ctx->authsize, alg->caam.geniv,
++ is_rfc3686, nonce, ctx1_iv_off, true,
++ priv->sec_attr.era);
++ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
++ dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT],
++ sizeof(flc->flc) + desc_bytes(desc),
++ ctx->dir);
++
++ return 0;
++}
++
++static int aead_setauthsize(struct crypto_aead *authenc, unsigned int authsize)
++{
++ struct caam_ctx *ctx = crypto_aead_ctx(authenc);
++
++ ctx->authsize = authsize;
++ aead_set_sh_desc(authenc);
++
++ return 0;
++}
++
++struct split_key_sh_result {
++ struct completion completion;
++ int err;
++ struct device *dev;
++};
++
++static void split_key_sh_done(void *cbk_ctx, u32 err)
++{
++ struct split_key_sh_result *res = cbk_ctx;
++
++#ifdef DEBUG
++ dev_err(res->dev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
++#endif
++
++ if (err)
++ caam_qi2_strstatus(res->dev, err);
++
++ res->err = err;
++ complete(&res->completion);
++}
++
++static int aead_setkey(struct crypto_aead *aead, const u8 *key,
++ unsigned int keylen)
++{
++ struct caam_ctx *ctx = crypto_aead_ctx(aead);
++ struct device *dev = ctx->dev;
++ struct crypto_authenc_keys keys;
++
++ if (crypto_authenc_extractkeys(&keys, key, keylen) != 0)
++ goto badkey;
++
++#ifdef DEBUG
++ dev_err(dev, "keylen %d enckeylen %d authkeylen %d\n",
++ keys.authkeylen + keys.enckeylen, keys.enckeylen,
++ keys.authkeylen);
++ print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
++#endif
++
++ ctx->adata.keylen = keys.authkeylen;
++ ctx->adata.keylen_pad = split_key_len(ctx->adata.algtype &
++ OP_ALG_ALGSEL_MASK);
++
++ if (ctx->adata.keylen_pad + keys.enckeylen > CAAM_MAX_KEY_SIZE)
++ goto badkey;
++
++ memcpy(ctx->key, keys.authkey, keys.authkeylen);
++ memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen);
++ dma_sync_single_for_device(dev, ctx->key_dma, ctx->adata.keylen_pad +
++ keys.enckeylen, ctx->dir);
++#ifdef DEBUG
++ print_hex_dump(KERN_ERR, "ctx.key@" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, ctx->key,
++ ctx->adata.keylen_pad + keys.enckeylen, 1);
++#endif
++
++ ctx->cdata.keylen = keys.enckeylen;
++
++ return aead_set_sh_desc(aead);
++badkey:
++ crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN);
++ return -EINVAL;
++}
++
++static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
++ bool encrypt)
++{
++ struct crypto_aead *aead = crypto_aead_reqtfm(req);
++ struct caam_request *req_ctx = aead_request_ctx(req);
++ struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1];
++ struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
++ struct caam_ctx *ctx = crypto_aead_ctx(aead);
++ struct caam_aead_alg *alg = container_of(crypto_aead_alg(aead),
++ typeof(*alg), aead);
++ struct device *dev = ctx->dev;
++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
++ GFP_KERNEL : GFP_ATOMIC;
++ int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0;
++ struct aead_edesc *edesc;
++ dma_addr_t qm_sg_dma, iv_dma = 0;
++ int ivsize = 0;
++ unsigned int authsize = ctx->authsize;
++ int qm_sg_index = 0, qm_sg_nents = 0, qm_sg_bytes;
++ int in_len, out_len;
++ struct dpaa2_sg_entry *sg_table;
++
++ /* allocate space for base edesc, link tables and IV */
++ edesc = qi_cache_zalloc(GFP_DMA | flags);
++ if (unlikely(!edesc)) {
++ dev_err(dev, "could not allocate extended descriptor\n");
++ return ERR_PTR(-ENOMEM);
++ }
++
++ if (unlikely(req->dst != req->src)) {
++ src_nents = sg_nents_for_len(req->src, req->assoclen +
++ req->cryptlen);
++ if (unlikely(src_nents < 0)) {
++ dev_err(dev, "Insufficient bytes (%d) in src S/G\n",
++ req->assoclen + req->cryptlen);
++ qi_cache_free(edesc);
++ return ERR_PTR(src_nents);
++ }
++
++ dst_nents = sg_nents_for_len(req->dst, req->assoclen +
++ req->cryptlen +
++ (encrypt ? authsize :
++ (-authsize)));
++ if (unlikely(dst_nents < 0)) {
++ dev_err(dev, "Insufficient bytes (%d) in dst S/G\n",
++ req->assoclen + req->cryptlen +
++ (encrypt ? authsize : (-authsize)));
++ qi_cache_free(edesc);
++ return ERR_PTR(dst_nents);
++ }
++
++ if (src_nents) {
++ mapped_src_nents = dma_map_sg(dev, req->src, src_nents,
++ DMA_TO_DEVICE);
++ if (unlikely(!mapped_src_nents)) {
++ dev_err(dev, "unable to map source\n");
++ qi_cache_free(edesc);
++ return ERR_PTR(-ENOMEM);
++ }
++ } else {
++ mapped_src_nents = 0;
++ }
++
++ mapped_dst_nents = dma_map_sg(dev, req->dst, dst_nents,
++ DMA_FROM_DEVICE);
++ if (unlikely(!mapped_dst_nents)) {
++ dev_err(dev, "unable to map destination\n");
++ dma_unmap_sg(dev, req->src, src_nents, DMA_TO_DEVICE);
++ qi_cache_free(edesc);
++ return ERR_PTR(-ENOMEM);
++ }
++ } else {
++ src_nents = sg_nents_for_len(req->src, req->assoclen +
++ req->cryptlen +
++ (encrypt ? authsize : 0));
++ if (unlikely(src_nents < 0)) {
++ dev_err(dev, "Insufficient bytes (%d) in src S/G\n",
++ req->assoclen + req->cryptlen +
++ (encrypt ? authsize : 0));
++ qi_cache_free(edesc);
++ return ERR_PTR(src_nents);
++ }
++
++ mapped_src_nents = dma_map_sg(dev, req->src, src_nents,
++ DMA_BIDIRECTIONAL);
++ if (unlikely(!mapped_src_nents)) {
++ dev_err(dev, "unable to map source\n");
++ qi_cache_free(edesc);
++ return ERR_PTR(-ENOMEM);
++ }
++ }
++
++ if ((alg->caam.rfc3686 && encrypt) || !alg->caam.geniv)
++ ivsize = crypto_aead_ivsize(aead);
++
++ /*
++ * Create S/G table: req->assoclen, [IV,] req->src [, req->dst].
++ * Input is not contiguous.
++ */
++ qm_sg_nents = 1 + !!ivsize + mapped_src_nents +
++ (mapped_dst_nents > 1 ? mapped_dst_nents : 0);
++ sg_table = &edesc->sgt[0];
++ qm_sg_bytes = qm_sg_nents * sizeof(*sg_table);
++ if (unlikely(offsetof(struct aead_edesc, sgt) + qm_sg_bytes + ivsize >
++ CAAM_QI_MEMCACHE_SIZE)) {
++ dev_err(dev, "No space for %d S/G entries and/or %dB IV\n",
++ qm_sg_nents, ivsize);
++ caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, 0,
++ 0, 0, 0);
++ qi_cache_free(edesc);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ if (ivsize) {
++ u8 *iv = (u8 *)(sg_table + qm_sg_nents);
++
++ /* Make sure IV is located in a DMAable area */
++ memcpy(iv, req->iv, ivsize);
++
++ iv_dma = dma_map_single(dev, iv, ivsize, DMA_TO_DEVICE);
++ if (dma_mapping_error(dev, iv_dma)) {
++ dev_err(dev, "unable to map IV\n");
++ caam_unmap(dev, req->src, req->dst, src_nents,
++ dst_nents, 0, 0, 0, 0);
++ qi_cache_free(edesc);
++ return ERR_PTR(-ENOMEM);
++ }
++ }
++
++ edesc->src_nents = src_nents;
++ edesc->dst_nents = dst_nents;
++ edesc->iv_dma = iv_dma;
++
++ edesc->assoclen = cpu_to_caam32(req->assoclen);
++ edesc->assoclen_dma = dma_map_single(dev, &edesc->assoclen, 4,
++ DMA_TO_DEVICE);
++ if (dma_mapping_error(dev, edesc->assoclen_dma)) {
++ dev_err(dev, "unable to map assoclen\n");
++ caam_unmap(dev, req->src, req->dst, src_nents, dst_nents,
++ iv_dma, ivsize, 0, 0);
++ qi_cache_free(edesc);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ dma_to_qm_sg_one(sg_table, edesc->assoclen_dma, 4, 0);
++ qm_sg_index++;
++ if (ivsize) {
++ dma_to_qm_sg_one(sg_table + qm_sg_index, iv_dma, ivsize, 0);
++ qm_sg_index++;
++ }
++ sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + qm_sg_index, 0);
++ qm_sg_index += mapped_src_nents;
++
++ if (mapped_dst_nents > 1)
++ sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table +
++ qm_sg_index, 0);
++
++ qm_sg_dma = dma_map_single(dev, sg_table, qm_sg_bytes, DMA_TO_DEVICE);
++ if (dma_mapping_error(dev, qm_sg_dma)) {
++ dev_err(dev, "unable to map S/G table\n");
++ dma_unmap_single(dev, edesc->assoclen_dma, 4, DMA_TO_DEVICE);
++ caam_unmap(dev, req->src, req->dst, src_nents, dst_nents,
++ iv_dma, ivsize, 0, 0);
++ qi_cache_free(edesc);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ edesc->qm_sg_dma = qm_sg_dma;
++ edesc->qm_sg_bytes = qm_sg_bytes;
++
++ out_len = req->assoclen + req->cryptlen +
++ (encrypt ? ctx->authsize : (-ctx->authsize));
++ in_len = 4 + ivsize + req->assoclen + req->cryptlen;
++
++ memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt));
++ dpaa2_fl_set_final(in_fle, true);
++ dpaa2_fl_set_format(in_fle, dpaa2_fl_sg);
++ dpaa2_fl_set_addr(in_fle, qm_sg_dma);
++ dpaa2_fl_set_len(in_fle, in_len);
++
++ if (req->dst == req->src) {
++ if (mapped_src_nents == 1) {
++ dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
++ dpaa2_fl_set_addr(out_fle, sg_dma_address(req->src));
++ } else {
++ dpaa2_fl_set_format(out_fle, dpaa2_fl_sg);
++ dpaa2_fl_set_addr(out_fle, qm_sg_dma +
++ (1 + !!ivsize) * sizeof(*sg_table));
++ }
++ } else if (mapped_dst_nents == 1) {
++ dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
++ dpaa2_fl_set_addr(out_fle, sg_dma_address(req->dst));
++ } else {
++ dpaa2_fl_set_format(out_fle, dpaa2_fl_sg);
++ dpaa2_fl_set_addr(out_fle, qm_sg_dma + qm_sg_index *
++ sizeof(*sg_table));
++ }
++
++ dpaa2_fl_set_len(out_fle, out_len);
++
++ return edesc;
++}
++
++static struct tls_edesc *tls_edesc_alloc(struct aead_request *req,
++ bool encrypt)
++{
++ struct crypto_aead *tls = crypto_aead_reqtfm(req);
++ unsigned int blocksize = crypto_aead_blocksize(tls);
++ unsigned int padsize, authsize;
++ struct caam_request *req_ctx = aead_request_ctx(req);
++ struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1];
++ struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
++ struct caam_ctx *ctx = crypto_aead_ctx(tls);
++ struct caam_aead_alg *alg = container_of(crypto_aead_alg(tls),
++ typeof(*alg), aead);
++ struct device *dev = ctx->dev;
++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
++ GFP_KERNEL : GFP_ATOMIC;
++ int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0;
++ struct tls_edesc *edesc;
++ dma_addr_t qm_sg_dma, iv_dma = 0;
++ int ivsize = 0;
++ u8 *iv;
++ int qm_sg_index, qm_sg_ents = 0, qm_sg_bytes;
++ int in_len, out_len;
++ struct dpaa2_sg_entry *sg_table;
++ struct scatterlist *dst;
++
++ if (encrypt) {
++ padsize = blocksize - ((req->cryptlen + ctx->authsize) %
++ blocksize);
++ authsize = ctx->authsize + padsize;
++ } else {
++ authsize = ctx->authsize;
++ }
++
++ /* allocate space for base edesc, link tables and IV */
++ edesc = qi_cache_zalloc(GFP_DMA | flags);
++ if (unlikely(!edesc)) {
++ dev_err(dev, "could not allocate extended descriptor\n");
++ return ERR_PTR(-ENOMEM);
++ }
++
++ if (likely(req->src == req->dst)) {
++ src_nents = sg_nents_for_len(req->src, req->assoclen +
++ req->cryptlen +
++ (encrypt ? authsize : 0));
++ if (unlikely(src_nents < 0)) {
++ dev_err(dev, "Insufficient bytes (%d) in src S/G\n",
++ req->assoclen + req->cryptlen +
++ (encrypt ? authsize : 0));
++ qi_cache_free(edesc);
++ return ERR_PTR(src_nents);
++ }
++
++ mapped_src_nents = dma_map_sg(dev, req->src, src_nents,
++ DMA_BIDIRECTIONAL);
++ if (unlikely(!mapped_src_nents)) {
++ dev_err(dev, "unable to map source\n");
++ qi_cache_free(edesc);
++ return ERR_PTR(-ENOMEM);
++ }
++ dst = req->dst;
++ } else {
++ src_nents = sg_nents_for_len(req->src, req->assoclen +
++ req->cryptlen);
++ if (unlikely(src_nents < 0)) {
++ dev_err(dev, "Insufficient bytes (%d) in src S/G\n",
++ req->assoclen + req->cryptlen);
++ qi_cache_free(edesc);
++ return ERR_PTR(src_nents);
++ }
++
++ dst = scatterwalk_ffwd(edesc->tmp, req->dst, req->assoclen);
++ dst_nents = sg_nents_for_len(dst, req->cryptlen +
++ (encrypt ? authsize : 0));
++ if (unlikely(dst_nents < 0)) {
++ dev_err(dev, "Insufficient bytes (%d) in dst S/G\n",
++ req->cryptlen +
++ (encrypt ? authsize : 0));
++ qi_cache_free(edesc);
++ return ERR_PTR(dst_nents);
++ }
++
++ if (src_nents) {
++ mapped_src_nents = dma_map_sg(dev, req->src,
++ src_nents, DMA_TO_DEVICE);
++ if (unlikely(!mapped_src_nents)) {
++ dev_err(dev, "unable to map source\n");
++ qi_cache_free(edesc);
++ return ERR_PTR(-ENOMEM);
++ }
++ } else {
++ mapped_src_nents = 0;
++ }
++
++ mapped_dst_nents = dma_map_sg(dev, dst, dst_nents,
++ DMA_FROM_DEVICE);
++ if (unlikely(!mapped_dst_nents)) {
++ dev_err(dev, "unable to map destination\n");
++ dma_unmap_sg(dev, req->src, src_nents, DMA_TO_DEVICE);
++ qi_cache_free(edesc);
++ return ERR_PTR(-ENOMEM);
++ }
++ }
++
++ /*
++ * Create S/G table: IV, src, dst.
++ * Input is not contiguous.
++ */
++ qm_sg_ents = 1 + mapped_src_nents +
++ (mapped_dst_nents > 1 ? mapped_dst_nents : 0);
++ sg_table = &edesc->sgt[0];
++ qm_sg_bytes = qm_sg_ents * sizeof(*sg_table);
++
++ ivsize = crypto_aead_ivsize(tls);
++ iv = (u8 *)(sg_table + qm_sg_ents);
++ /* Make sure IV is located in a DMAable area */
++ memcpy(iv, req->iv, ivsize);
++ iv_dma = dma_map_single(dev, iv, ivsize, DMA_TO_DEVICE);
++ if (dma_mapping_error(dev, iv_dma)) {
++ dev_err(dev, "unable to map IV\n");
++ caam_unmap(dev, req->src, dst, src_nents, dst_nents, 0, 0, 0,
++ 0);
++ qi_cache_free(edesc);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ edesc->src_nents = src_nents;
++ edesc->dst_nents = dst_nents;
++ edesc->dst = dst;
++ edesc->iv_dma = iv_dma;
++
++ dma_to_qm_sg_one(sg_table, iv_dma, ivsize, 0);
++ qm_sg_index = 1;
++
++ sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + qm_sg_index, 0);
++ qm_sg_index += mapped_src_nents;
++
++ if (mapped_dst_nents > 1)
++ sg_to_qm_sg_last(dst, mapped_dst_nents, sg_table +
++ qm_sg_index, 0);
++
++ qm_sg_dma = dma_map_single(dev, sg_table, qm_sg_bytes, DMA_TO_DEVICE);
++ if (dma_mapping_error(dev, qm_sg_dma)) {
++ dev_err(dev, "unable to map S/G table\n");
++ caam_unmap(dev, req->src, dst, src_nents, dst_nents, iv_dma,
++ ivsize, 0, 0);
++ qi_cache_free(edesc);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ edesc->qm_sg_dma = qm_sg_dma;
++ edesc->qm_sg_bytes = qm_sg_bytes;
++
++ out_len = req->cryptlen + (encrypt ? authsize : 0);
++ in_len = ivsize + req->assoclen + req->cryptlen;
++
++ memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt));
++ dpaa2_fl_set_final(in_fle, true);
++ dpaa2_fl_set_format(in_fle, dpaa2_fl_sg);
++ dpaa2_fl_set_addr(in_fle, qm_sg_dma);
++ dpaa2_fl_set_len(in_fle, in_len);
++
++ if (req->dst == req->src) {
++ dpaa2_fl_set_format(out_fle, dpaa2_fl_sg);
++ dpaa2_fl_set_addr(out_fle, qm_sg_dma +
++ (sg_nents_for_len(req->src, req->assoclen) +
++ 1) * sizeof(*sg_table));
++ } else if (mapped_dst_nents == 1) {
++ dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
++ dpaa2_fl_set_addr(out_fle, sg_dma_address(dst));
++ } else {
++ dpaa2_fl_set_format(out_fle, dpaa2_fl_sg);
++ dpaa2_fl_set_addr(out_fle, qm_sg_dma + qm_sg_index *
++ sizeof(*sg_table));
++ }
++
++ dpaa2_fl_set_len(out_fle, out_len);
++
++ return edesc;
++}
++
++static int tls_set_sh_desc(struct crypto_aead *tls)
++{
++ struct caam_ctx *ctx = crypto_aead_ctx(tls);
++ unsigned int ivsize = crypto_aead_ivsize(tls);
++ unsigned int blocksize = crypto_aead_blocksize(tls);
++ struct device *dev = ctx->dev;
++ struct dpaa2_caam_priv *priv = dev_get_drvdata(dev);
++ struct caam_flc *flc;
++ u32 *desc;
++ unsigned int assoclen = 13; /* always 13 bytes for TLS */
++ unsigned int data_len[2];
++ u32 inl_mask;
++
++ if (!ctx->cdata.keylen || !ctx->authsize)
++ return 0;
++
++ /*
++ * TLS 1.0 encrypt shared descriptor
++ * Job Descriptor and Shared Descriptor
++ * must fit into the 64-word Descriptor h/w Buffer
++ */
++ data_len[0] = ctx->adata.keylen_pad;
++ data_len[1] = ctx->cdata.keylen;
++
++ if (desc_inline_query(DESC_TLS10_ENC_LEN, DESC_JOB_IO_LEN, data_len,
++ &inl_mask, ARRAY_SIZE(data_len)) < 0)
++ return -EINVAL;
++
++ if (inl_mask & 1)
++ ctx->adata.key_virt = ctx->key;
++ else
++ ctx->adata.key_dma = ctx->key_dma;
++
++ if (inl_mask & 2)
++ ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad;
++ else
++ ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad;
++
++ ctx->adata.key_inline = !!(inl_mask & 1);
++ ctx->cdata.key_inline = !!(inl_mask & 2);
++
++ flc = &ctx->flc[ENCRYPT];
++ desc = flc->sh_desc;
++ cnstr_shdsc_tls_encap(desc, &ctx->cdata, &ctx->adata,
++ assoclen, ivsize, ctx->authsize, blocksize,
++ priv->sec_attr.era);
++ flc->flc[1] = cpu_to_caam32(desc_len(desc));
++ dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT],
++ sizeof(flc->flc) + desc_bytes(desc),
++ ctx->dir);
++
++ /*
++ * TLS 1.0 decrypt shared descriptor
++ * Keys do not fit inline, regardless of algorithms used
++ */
++ ctx->adata.key_inline = false;
++ ctx->adata.key_dma = ctx->key_dma;
++ ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad;
++
++ flc = &ctx->flc[DECRYPT];
++ desc = flc->sh_desc;
++ cnstr_shdsc_tls_decap(desc, &ctx->cdata, &ctx->adata, assoclen, ivsize,
++ ctx->authsize, blocksize, priv->sec_attr.era);
++ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
++ dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT],
++ sizeof(flc->flc) + desc_bytes(desc),
++ ctx->dir);
++
++ return 0;
++}
++
++static int tls_setkey(struct crypto_aead *tls, const u8 *key,
++ unsigned int keylen)
++{
++ struct caam_ctx *ctx = crypto_aead_ctx(tls);
++ struct device *dev = ctx->dev;
++ struct crypto_authenc_keys keys;
++
++ if (crypto_authenc_extractkeys(&keys, key, keylen) != 0)
++ goto badkey;
++
++#ifdef DEBUG
++ dev_err(dev, "keylen %d enckeylen %d authkeylen %d\n",
++ keys.authkeylen + keys.enckeylen, keys.enckeylen,
++ keys.authkeylen);
++ print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
++#endif
++
++ ctx->adata.keylen = keys.authkeylen;
++ ctx->adata.keylen_pad = split_key_len(ctx->adata.algtype &
++ OP_ALG_ALGSEL_MASK);
++
++ if (ctx->adata.keylen_pad + keys.enckeylen > CAAM_MAX_KEY_SIZE)
++ goto badkey;
++
++ memcpy(ctx->key, keys.authkey, keys.authkeylen);
++ memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen);
++ dma_sync_single_for_device(dev, ctx->key_dma, ctx->adata.keylen_pad +
++ keys.enckeylen, ctx->dir);
++#ifdef DEBUG
++ print_hex_dump(KERN_ERR, "ctx.key@" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, ctx->key,
++ ctx->adata.keylen_pad + keys.enckeylen, 1);
++#endif
++
++ ctx->cdata.keylen = keys.enckeylen;
++
++ return tls_set_sh_desc(tls);
++badkey:
++ crypto_aead_set_flags(tls, CRYPTO_TFM_RES_BAD_KEY_LEN);
++ return -EINVAL;
++}
++
++static int tls_setauthsize(struct crypto_aead *tls, unsigned int authsize)
++{
++ struct caam_ctx *ctx = crypto_aead_ctx(tls);
++
++ ctx->authsize = authsize;
++ tls_set_sh_desc(tls);
++
++ return 0;
++}
++
++static int gcm_set_sh_desc(struct crypto_aead *aead)
++{
++ struct caam_ctx *ctx = crypto_aead_ctx(aead);
++ struct device *dev = ctx->dev;
++ unsigned int ivsize = crypto_aead_ivsize(aead);
++ struct caam_flc *flc;
++ u32 *desc;
++ int rem_bytes = CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN -
++ ctx->cdata.keylen;
++
++ if (!ctx->cdata.keylen || !ctx->authsize)
++ return 0;
++
++ /*
++ * AES GCM encrypt shared descriptor
++ * Job Descriptor and Shared Descriptor
++ * must fit into the 64-word Descriptor h/w Buffer
++ */
++ if (rem_bytes >= DESC_QI_GCM_ENC_LEN) {
++ ctx->cdata.key_inline = true;
++ ctx->cdata.key_virt = ctx->key;
++ } else {
++ ctx->cdata.key_inline = false;
++ ctx->cdata.key_dma = ctx->key_dma;
++ }
++
++ flc = &ctx->flc[ENCRYPT];
++ desc = flc->sh_desc;
++ cnstr_shdsc_gcm_encap(desc, &ctx->cdata, ivsize, ctx->authsize, true);
++ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
++ dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT],
++ sizeof(flc->flc) + desc_bytes(desc),
++ ctx->dir);
++
++ /*
++ * Job Descriptor and Shared Descriptors
++ * must all fit into the 64-word Descriptor h/w Buffer
++ */
++ if (rem_bytes >= DESC_QI_GCM_DEC_LEN) {
++ ctx->cdata.key_inline = true;
++ ctx->cdata.key_virt = ctx->key;
++ } else {
++ ctx->cdata.key_inline = false;
++ ctx->cdata.key_dma = ctx->key_dma;
++ }
++
++ flc = &ctx->flc[DECRYPT];
++ desc = flc->sh_desc;
++ cnstr_shdsc_gcm_decap(desc, &ctx->cdata, ivsize, ctx->authsize, true);
++ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
++ dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT],
++ sizeof(flc->flc) + desc_bytes(desc),
++ ctx->dir);
++
++ return 0;
++}
++
++static int gcm_setauthsize(struct crypto_aead *authenc, unsigned int authsize)
++{
++ struct caam_ctx *ctx = crypto_aead_ctx(authenc);
++
++ ctx->authsize = authsize;
++ gcm_set_sh_desc(authenc);
++
++ return 0;
++}
++
++static int gcm_setkey(struct crypto_aead *aead,
++ const u8 *key, unsigned int keylen)
++{
++ struct caam_ctx *ctx = crypto_aead_ctx(aead);
++ struct device *dev = ctx->dev;
++
++#ifdef DEBUG
++ print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
++#endif
++
++ memcpy(ctx->key, key, keylen);
++ dma_sync_single_for_device(dev, ctx->key_dma, keylen, ctx->dir);
++ ctx->cdata.keylen = keylen;
++
++ return gcm_set_sh_desc(aead);
++}
++
++static int rfc4106_set_sh_desc(struct crypto_aead *aead)
++{
++ struct caam_ctx *ctx = crypto_aead_ctx(aead);
++ struct device *dev = ctx->dev;
++ unsigned int ivsize = crypto_aead_ivsize(aead);
++ struct caam_flc *flc;
++ u32 *desc;
++ int rem_bytes = CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN -
++ ctx->cdata.keylen;
++
++ if (!ctx->cdata.keylen || !ctx->authsize)
++ return 0;
++
++ ctx->cdata.key_virt = ctx->key;
++
++ /*
++ * RFC4106 encrypt shared descriptor
++ * Job Descriptor and Shared Descriptor
++ * must fit into the 64-word Descriptor h/w Buffer
++ */
++ if (rem_bytes >= DESC_QI_RFC4106_ENC_LEN) {
++ ctx->cdata.key_inline = true;
++ } else {
++ ctx->cdata.key_inline = false;
++ ctx->cdata.key_dma = ctx->key_dma;
++ }
++
++ flc = &ctx->flc[ENCRYPT];
++ desc = flc->sh_desc;
++ cnstr_shdsc_rfc4106_encap(desc, &ctx->cdata, ivsize, ctx->authsize,
++ true);
++ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
++ dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT],
++ sizeof(flc->flc) + desc_bytes(desc),
++ ctx->dir);
++
++ /*
++ * Job Descriptor and Shared Descriptors
++ * must all fit into the 64-word Descriptor h/w Buffer
++ */
++ if (rem_bytes >= DESC_QI_RFC4106_DEC_LEN) {
++ ctx->cdata.key_inline = true;
++ } else {
++ ctx->cdata.key_inline = false;
++ ctx->cdata.key_dma = ctx->key_dma;
++ }
++
++ flc = &ctx->flc[DECRYPT];
++ desc = flc->sh_desc;
++ cnstr_shdsc_rfc4106_decap(desc, &ctx->cdata, ivsize, ctx->authsize,
++ true);
++ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
++ dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT],
++ sizeof(flc->flc) + desc_bytes(desc),
++ ctx->dir);
++
++ return 0;
++}
++
++static int rfc4106_setauthsize(struct crypto_aead *authenc,
++ unsigned int authsize)
++{
++ struct caam_ctx *ctx = crypto_aead_ctx(authenc);
++
++ ctx->authsize = authsize;
++ rfc4106_set_sh_desc(authenc);
++
++ return 0;
++}
++
++static int rfc4106_setkey(struct crypto_aead *aead,
++ const u8 *key, unsigned int keylen)
++{
++ struct caam_ctx *ctx = crypto_aead_ctx(aead);
++ struct device *dev = ctx->dev;
++
++ if (keylen < 4)
++ return -EINVAL;
++
++#ifdef DEBUG
++ print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
++#endif
++
++ memcpy(ctx->key, key, keylen);
++ /*
++ * The last four bytes of the key material are used as the salt value
++ * in the nonce. Update the AES key length.
++ */
++ ctx->cdata.keylen = keylen - 4;
++ dma_sync_single_for_device(dev, ctx->key_dma, ctx->cdata.keylen,
++ ctx->dir);
++
++ return rfc4106_set_sh_desc(aead);
++}
++
++static int rfc4543_set_sh_desc(struct crypto_aead *aead)
++{
++ struct caam_ctx *ctx = crypto_aead_ctx(aead);
++ struct device *dev = ctx->dev;
++ unsigned int ivsize = crypto_aead_ivsize(aead);
++ struct caam_flc *flc;
++ u32 *desc;
++ int rem_bytes = CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN -
++ ctx->cdata.keylen;
++
++ if (!ctx->cdata.keylen || !ctx->authsize)
++ return 0;
++
++ ctx->cdata.key_virt = ctx->key;
++
++ /*
++ * RFC4543 encrypt shared descriptor
++ * Job Descriptor and Shared Descriptor
++ * must fit into the 64-word Descriptor h/w Buffer
++ */
++ if (rem_bytes >= DESC_QI_RFC4543_ENC_LEN) {
++ ctx->cdata.key_inline = true;
++ } else {
++ ctx->cdata.key_inline = false;
++ ctx->cdata.key_dma = ctx->key_dma;
++ }
++
++ flc = &ctx->flc[ENCRYPT];
++ desc = flc->sh_desc;
++ cnstr_shdsc_rfc4543_encap(desc, &ctx->cdata, ivsize, ctx->authsize,
++ true);
++ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
++ dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT],
++ sizeof(flc->flc) + desc_bytes(desc),
++ ctx->dir);
++
++ /*
++ * Job Descriptor and Shared Descriptors
++ * must all fit into the 64-word Descriptor h/w Buffer
++ */
++ if (rem_bytes >= DESC_QI_RFC4543_DEC_LEN) {
++ ctx->cdata.key_inline = true;
++ } else {
++ ctx->cdata.key_inline = false;
++ ctx->cdata.key_dma = ctx->key_dma;
++ }
++
++ flc = &ctx->flc[DECRYPT];
++ desc = flc->sh_desc;
++ cnstr_shdsc_rfc4543_decap(desc, &ctx->cdata, ivsize, ctx->authsize,
++ true);
++ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
++ dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT],
++ sizeof(flc->flc) + desc_bytes(desc),
++ ctx->dir);
++
++ return 0;
++}
++
++static int rfc4543_setauthsize(struct crypto_aead *authenc,
++ unsigned int authsize)
++{
++ struct caam_ctx *ctx = crypto_aead_ctx(authenc);
++
++ ctx->authsize = authsize;
++ rfc4543_set_sh_desc(authenc);
++
++ return 0;
++}
++
++static int rfc4543_setkey(struct crypto_aead *aead,
++ const u8 *key, unsigned int keylen)
++{
++ struct caam_ctx *ctx = crypto_aead_ctx(aead);
++ struct device *dev = ctx->dev;
++
++ if (keylen < 4)
++ return -EINVAL;
++
++#ifdef DEBUG
++ print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
++#endif
++
++ memcpy(ctx->key, key, keylen);
++ /*
++ * The last four bytes of the key material are used as the salt value
++ * in the nonce. Update the AES key length.
++ */
++ ctx->cdata.keylen = keylen - 4;
++ dma_sync_single_for_device(dev, ctx->key_dma, ctx->cdata.keylen,
++ ctx->dir);
++
++ return rfc4543_set_sh_desc(aead);
++}
++
++static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key,
++ unsigned int keylen)
++{
++ struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
++ struct caam_skcipher_alg *alg =
++ container_of(crypto_skcipher_alg(skcipher),
++ struct caam_skcipher_alg, skcipher);
++ struct device *dev = ctx->dev;
++ struct caam_flc *flc;
++ unsigned int ivsize = crypto_skcipher_ivsize(skcipher);
++ u32 *desc;
++ u32 ctx1_iv_off = 0;
++ const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) ==
++ OP_ALG_AAI_CTR_MOD128);
++ const bool is_rfc3686 = alg->caam.rfc3686;
++
++#ifdef DEBUG
++ print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
++#endif
++ /*
++ * AES-CTR needs to load IV in CONTEXT1 reg
++ * at an offset of 128bits (16bytes)
++ * CONTEXT1[255:128] = IV
++ */
++ if (ctr_mode)
++ ctx1_iv_off = 16;
++
++ /*
++ * RFC3686 specific:
++ * | CONTEXT1[255:128] = {NONCE, IV, COUNTER}
++ * | *key = {KEY, NONCE}
++ */
++ if (is_rfc3686) {
++ ctx1_iv_off = 16 + CTR_RFC3686_NONCE_SIZE;
++ keylen -= CTR_RFC3686_NONCE_SIZE;
++ }
++
++ ctx->cdata.keylen = keylen;
++ ctx->cdata.key_virt = key;
++ ctx->cdata.key_inline = true;
++
++ /* skcipher_encrypt shared descriptor */
++ flc = &ctx->flc[ENCRYPT];
++ desc = flc->sh_desc;
++ cnstr_shdsc_ablkcipher_encap(desc, &ctx->cdata, ivsize,
++ is_rfc3686, ctx1_iv_off);
++ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
++ dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT],
++ sizeof(flc->flc) + desc_bytes(desc),
++ ctx->dir);
++
++ /* skcipher_decrypt shared descriptor */
++ flc = &ctx->flc[DECRYPT];
++ desc = flc->sh_desc;
++ cnstr_shdsc_ablkcipher_decap(desc, &ctx->cdata, ivsize,
++ is_rfc3686, ctx1_iv_off);
++ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
++ dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT],
++ sizeof(flc->flc) + desc_bytes(desc),
++ ctx->dir);
++
++ return 0;
++}
++
++static int xts_skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key,
++ unsigned int keylen)
++{
++ struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
++ struct device *dev = ctx->dev;
++ struct caam_flc *flc;
++ u32 *desc;
++
++ if (keylen != 2 * AES_MIN_KEY_SIZE && keylen != 2 * AES_MAX_KEY_SIZE) {
++ dev_err(dev, "key size mismatch\n");
++ crypto_skcipher_set_flags(skcipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
++ return -EINVAL;
++ }
++
++ ctx->cdata.keylen = keylen;
++ ctx->cdata.key_virt = key;
++ ctx->cdata.key_inline = true;
++
++ /* xts_skcipher_encrypt shared descriptor */
++ flc = &ctx->flc[ENCRYPT];
++ desc = flc->sh_desc;
++ cnstr_shdsc_xts_ablkcipher_encap(desc, &ctx->cdata);
++ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
++ dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT],
++ sizeof(flc->flc) + desc_bytes(desc),
++ ctx->dir);
++
++ /* xts_skcipher_decrypt shared descriptor */
++ flc = &ctx->flc[DECRYPT];
++ desc = flc->sh_desc;
++ cnstr_shdsc_xts_ablkcipher_decap(desc, &ctx->cdata);
++ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
++ dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT],
++ sizeof(flc->flc) + desc_bytes(desc),
++ ctx->dir);
++
++ return 0;
++}
++
++static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req)
++{
++ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
++ struct caam_request *req_ctx = skcipher_request_ctx(req);
++ struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1];
++ struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
++ struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
++ struct device *dev = ctx->dev;
++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
++ GFP_KERNEL : GFP_ATOMIC;
++ int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0;
++ struct skcipher_edesc *edesc;
++ dma_addr_t iv_dma;
++ u8 *iv;
++ int ivsize = crypto_skcipher_ivsize(skcipher);
++ int dst_sg_idx, qm_sg_ents, qm_sg_bytes;
++ struct dpaa2_sg_entry *sg_table;
++
++ src_nents = sg_nents_for_len(req->src, req->cryptlen);
++ if (unlikely(src_nents < 0)) {
++ dev_err(dev, "Insufficient bytes (%d) in src S/G\n",
++ req->cryptlen);
++ return ERR_PTR(src_nents);
++ }
++
++ if (unlikely(req->dst != req->src)) {
++ dst_nents = sg_nents_for_len(req->dst, req->cryptlen);
++ if (unlikely(dst_nents < 0)) {
++ dev_err(dev, "Insufficient bytes (%d) in dst S/G\n",
++ req->cryptlen);
++ return ERR_PTR(dst_nents);
++ }
++
++ mapped_src_nents = dma_map_sg(dev, req->src, src_nents,
++ DMA_TO_DEVICE);
++ if (unlikely(!mapped_src_nents)) {
++ dev_err(dev, "unable to map source\n");
++ return ERR_PTR(-ENOMEM);
++ }
++
++ mapped_dst_nents = dma_map_sg(dev, req->dst, dst_nents,
++ DMA_FROM_DEVICE);
++ if (unlikely(!mapped_dst_nents)) {
++ dev_err(dev, "unable to map destination\n");
++ dma_unmap_sg(dev, req->src, src_nents, DMA_TO_DEVICE);
++ return ERR_PTR(-ENOMEM);
++ }
++ } else {
++ mapped_src_nents = dma_map_sg(dev, req->src, src_nents,
++ DMA_BIDIRECTIONAL);
++ if (unlikely(!mapped_src_nents)) {
++ dev_err(dev, "unable to map source\n");
++ return ERR_PTR(-ENOMEM);
++ }
++ }
++
++ qm_sg_ents = 1 + mapped_src_nents;
++ dst_sg_idx = qm_sg_ents;
++
++ qm_sg_ents += mapped_dst_nents > 1 ? mapped_dst_nents : 0;
++ qm_sg_bytes = qm_sg_ents * sizeof(struct dpaa2_sg_entry);
++ if (unlikely(offsetof(struct skcipher_edesc, sgt) + qm_sg_bytes +
++ ivsize > CAAM_QI_MEMCACHE_SIZE)) {
++ dev_err(dev, "No space for %d S/G entries and/or %dB IV\n",
++ qm_sg_ents, ivsize);
++ caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, 0,
++ 0, 0, 0);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ /* allocate space for base edesc, link tables and IV */
++ edesc = qi_cache_zalloc(GFP_DMA | flags);
++ if (unlikely(!edesc)) {
++ dev_err(dev, "could not allocate extended descriptor\n");
++ caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, 0,
++ 0, 0, 0);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ /* Make sure IV is located in a DMAable area */
++ sg_table = &edesc->sgt[0];
++ iv = (u8 *)(sg_table + qm_sg_ents);
++ memcpy(iv, req->iv, ivsize);
++
++ iv_dma = dma_map_single(dev, iv, ivsize, DMA_TO_DEVICE);
++ if (dma_mapping_error(dev, iv_dma)) {
++ dev_err(dev, "unable to map IV\n");
++ caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, 0,
++ 0, 0, 0);
++ qi_cache_free(edesc);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ edesc->src_nents = src_nents;
++ edesc->dst_nents = dst_nents;
++ edesc->iv_dma = iv_dma;
++ edesc->qm_sg_bytes = qm_sg_bytes;
++
++ dma_to_qm_sg_one(sg_table, iv_dma, ivsize, 0);
++ sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + 1, 0);
++
++ if (mapped_dst_nents > 1)
++ sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table +
++ dst_sg_idx, 0);
++
++ edesc->qm_sg_dma = dma_map_single(dev, sg_table, edesc->qm_sg_bytes,
++ DMA_TO_DEVICE);
++ if (dma_mapping_error(dev, edesc->qm_sg_dma)) {
++ dev_err(dev, "unable to map S/G table\n");
++ caam_unmap(dev, req->src, req->dst, src_nents, dst_nents,
++ iv_dma, ivsize, 0, 0);
++ qi_cache_free(edesc);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt));
++ dpaa2_fl_set_final(in_fle, true);
++ dpaa2_fl_set_len(in_fle, req->cryptlen + ivsize);
++ dpaa2_fl_set_len(out_fle, req->cryptlen);
++
++ dpaa2_fl_set_format(in_fle, dpaa2_fl_sg);
++ dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma);
++
++ if (req->src == req->dst) {
++ dpaa2_fl_set_format(out_fle, dpaa2_fl_sg);
++ dpaa2_fl_set_addr(out_fle, edesc->qm_sg_dma +
++ sizeof(*sg_table));
++ } else if (mapped_dst_nents > 1) {
++ dpaa2_fl_set_format(out_fle, dpaa2_fl_sg);
++ dpaa2_fl_set_addr(out_fle, edesc->qm_sg_dma + dst_sg_idx *
++ sizeof(*sg_table));
++ } else {
++ dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
++ dpaa2_fl_set_addr(out_fle, sg_dma_address(req->dst));
++ }
++
++ return edesc;
++}
++
++static void aead_unmap(struct device *dev, struct aead_edesc *edesc,
++ struct aead_request *req)
++{
++ struct crypto_aead *aead = crypto_aead_reqtfm(req);
++ int ivsize = crypto_aead_ivsize(aead);
++
++ caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents,
++ edesc->iv_dma, ivsize, edesc->qm_sg_dma, edesc->qm_sg_bytes);
++ dma_unmap_single(dev, edesc->assoclen_dma, 4, DMA_TO_DEVICE);
++}
++
++static void tls_unmap(struct device *dev, struct tls_edesc *edesc,
++ struct aead_request *req)
++{
++ struct crypto_aead *tls = crypto_aead_reqtfm(req);
++ int ivsize = crypto_aead_ivsize(tls);
++
++ caam_unmap(dev, req->src, edesc->dst, edesc->src_nents,
++ edesc->dst_nents, edesc->iv_dma, ivsize, edesc->qm_sg_dma,
++ edesc->qm_sg_bytes);
++}
++
++static void skcipher_unmap(struct device *dev, struct skcipher_edesc *edesc,
++ struct skcipher_request *req)
++{
++ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
++ int ivsize = crypto_skcipher_ivsize(skcipher);
++
++ caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents,
++ edesc->iv_dma, ivsize, edesc->qm_sg_dma, edesc->qm_sg_bytes);
++}
++
++static void aead_encrypt_done(void *cbk_ctx, u32 status)
++{
++ struct crypto_async_request *areq = cbk_ctx;
++ struct aead_request *req = container_of(areq, struct aead_request,
++ base);
++ struct caam_request *req_ctx = to_caam_req(areq);
++ struct aead_edesc *edesc = req_ctx->edesc;
++ struct crypto_aead *aead = crypto_aead_reqtfm(req);
++ struct caam_ctx *ctx = crypto_aead_ctx(aead);
++ int ecode = 0;
++
++#ifdef DEBUG
++ dev_err(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status);
++#endif
++
++ if (unlikely(status)) {
++ caam_qi2_strstatus(ctx->dev, status);
++ ecode = -EIO;
++ }
++
++ aead_unmap(ctx->dev, edesc, req);
++ qi_cache_free(edesc);
++ aead_request_complete(req, ecode);
++}
++
++static void aead_decrypt_done(void *cbk_ctx, u32 status)
++{
++ struct crypto_async_request *areq = cbk_ctx;
++ struct aead_request *req = container_of(areq, struct aead_request,
++ base);
++ struct caam_request *req_ctx = to_caam_req(areq);
++ struct aead_edesc *edesc = req_ctx->edesc;
++ struct crypto_aead *aead = crypto_aead_reqtfm(req);
++ struct caam_ctx *ctx = crypto_aead_ctx(aead);
++ int ecode = 0;
++
++#ifdef DEBUG
++ dev_err(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status);
++#endif
++
++ if (unlikely(status)) {
++ caam_qi2_strstatus(ctx->dev, status);
++ /*
++ * verify hw auth check passed else return -EBADMSG
++ */
++ if ((status & JRSTA_CCBERR_ERRID_MASK) ==
++ JRSTA_CCBERR_ERRID_ICVCHK)
++ ecode = -EBADMSG;
++ else
++ ecode = -EIO;
++ }
++
++ aead_unmap(ctx->dev, edesc, req);
++ qi_cache_free(edesc);
++ aead_request_complete(req, ecode);
++}
++
++static int aead_encrypt(struct aead_request *req)
++{
++ struct aead_edesc *edesc;
++ struct crypto_aead *aead = crypto_aead_reqtfm(req);
++ struct caam_ctx *ctx = crypto_aead_ctx(aead);
++ struct caam_request *caam_req = aead_request_ctx(req);
++ int ret;
++
++ /* allocate extended descriptor */
++ edesc = aead_edesc_alloc(req, true);
++ if (IS_ERR(edesc))
++ return PTR_ERR(edesc);
++
++ caam_req->flc = &ctx->flc[ENCRYPT];
++ caam_req->flc_dma = ctx->flc_dma[ENCRYPT];
++ caam_req->cbk = aead_encrypt_done;
++ caam_req->ctx = &req->base;
++ caam_req->edesc = edesc;
++ ret = dpaa2_caam_enqueue(ctx->dev, caam_req);
++ if (ret != -EINPROGRESS &&
++ !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
++ aead_unmap(ctx->dev, edesc, req);
++ qi_cache_free(edesc);
++ }
++
++ return ret;
++}
++
++static int aead_decrypt(struct aead_request *req)
++{
++ struct aead_edesc *edesc;
++ struct crypto_aead *aead = crypto_aead_reqtfm(req);
++ struct caam_ctx *ctx = crypto_aead_ctx(aead);
++ struct caam_request *caam_req = aead_request_ctx(req);
++ int ret;
++
++ /* allocate extended descriptor */
++ edesc = aead_edesc_alloc(req, false);
++ if (IS_ERR(edesc))
++ return PTR_ERR(edesc);
++
++ caam_req->flc = &ctx->flc[DECRYPT];
++ caam_req->flc_dma = ctx->flc_dma[DECRYPT];
++ caam_req->cbk = aead_decrypt_done;
++ caam_req->ctx = &req->base;
++ caam_req->edesc = edesc;
++ ret = dpaa2_caam_enqueue(ctx->dev, caam_req);
++ if (ret != -EINPROGRESS &&
++ !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
++ aead_unmap(ctx->dev, edesc, req);
++ qi_cache_free(edesc);
++ }
++
++ return ret;
++}
++
++static void tls_encrypt_done(void *cbk_ctx, u32 status)
++{
++ struct crypto_async_request *areq = cbk_ctx;
++ struct aead_request *req = container_of(areq, struct aead_request,
++ base);
++ struct caam_request *req_ctx = to_caam_req(areq);
++ struct tls_edesc *edesc = req_ctx->edesc;
++ struct crypto_aead *tls = crypto_aead_reqtfm(req);
++ struct caam_ctx *ctx = crypto_aead_ctx(tls);
++ int ecode = 0;
++
++#ifdef DEBUG
++ dev_err(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status);
++#endif
++
++ if (unlikely(status)) {
++ caam_qi2_strstatus(ctx->dev, status);
++ ecode = -EIO;
++ }
++
++ tls_unmap(ctx->dev, edesc, req);
++ qi_cache_free(edesc);
++ aead_request_complete(req, ecode);
++}
++
++static void tls_decrypt_done(void *cbk_ctx, u32 status)
++{
++ struct crypto_async_request *areq = cbk_ctx;
++ struct aead_request *req = container_of(areq, struct aead_request,
++ base);
++ struct caam_request *req_ctx = to_caam_req(areq);
++ struct tls_edesc *edesc = req_ctx->edesc;
++ struct crypto_aead *tls = crypto_aead_reqtfm(req);
++ struct caam_ctx *ctx = crypto_aead_ctx(tls);
++ int ecode = 0;
++
++#ifdef DEBUG
++ dev_err(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status);
++#endif
++
++ if (unlikely(status)) {
++ caam_qi2_strstatus(ctx->dev, status);
++ /*
++ * verify hw auth check passed else return -EBADMSG
++ */
++ if ((status & JRSTA_CCBERR_ERRID_MASK) ==
++ JRSTA_CCBERR_ERRID_ICVCHK)
++ ecode = -EBADMSG;
++ else
++ ecode = -EIO;
++ }
++
++ tls_unmap(ctx->dev, edesc, req);
++ qi_cache_free(edesc);
++ aead_request_complete(req, ecode);
++}
++
++static int tls_encrypt(struct aead_request *req)
++{
++ struct tls_edesc *edesc;
++ struct crypto_aead *tls = crypto_aead_reqtfm(req);
++ struct caam_ctx *ctx = crypto_aead_ctx(tls);
++ struct caam_request *caam_req = aead_request_ctx(req);
++ int ret;
++
++ /* allocate extended descriptor */
++ edesc = tls_edesc_alloc(req, true);
++ if (IS_ERR(edesc))
++ return PTR_ERR(edesc);
++
++ caam_req->flc = &ctx->flc[ENCRYPT];
++ caam_req->flc_dma = ctx->flc_dma[ENCRYPT];
++ caam_req->cbk = tls_encrypt_done;
++ caam_req->ctx = &req->base;
++ caam_req->edesc = edesc;
++ ret = dpaa2_caam_enqueue(ctx->dev, caam_req);
++ if (ret != -EINPROGRESS &&
++ !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
++ tls_unmap(ctx->dev, edesc, req);
++ qi_cache_free(edesc);
++ }
++
++ return ret;
++}
++
++static int tls_decrypt(struct aead_request *req)
++{
++ struct tls_edesc *edesc;
++ struct crypto_aead *tls = crypto_aead_reqtfm(req);
++ struct caam_ctx *ctx = crypto_aead_ctx(tls);
++ struct caam_request *caam_req = aead_request_ctx(req);
++ int ret;
++
++ /* allocate extended descriptor */
++ edesc = tls_edesc_alloc(req, false);
++ if (IS_ERR(edesc))
++ return PTR_ERR(edesc);
++
++ caam_req->flc = &ctx->flc[DECRYPT];
++ caam_req->flc_dma = ctx->flc_dma[DECRYPT];
++ caam_req->cbk = tls_decrypt_done;
++ caam_req->ctx = &req->base;
++ caam_req->edesc = edesc;
++ ret = dpaa2_caam_enqueue(ctx->dev, caam_req);
++ if (ret != -EINPROGRESS &&
++ !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
++ tls_unmap(ctx->dev, edesc, req);
++ qi_cache_free(edesc);
++ }
++
++ return ret;
++}
++
++static int ipsec_gcm_encrypt(struct aead_request *req)
++{
++ if (req->assoclen < 8)
++ return -EINVAL;
++
++ return aead_encrypt(req);
++}
++
++static int ipsec_gcm_decrypt(struct aead_request *req)
++{
++ if (req->assoclen < 8)
++ return -EINVAL;
++
++ return aead_decrypt(req);
++}
++
++static void skcipher_encrypt_done(void *cbk_ctx, u32 status)
++{
++ struct crypto_async_request *areq = cbk_ctx;
++ struct skcipher_request *req = skcipher_request_cast(areq);
++ struct caam_request *req_ctx = to_caam_req(areq);
++ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
++ struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
++ struct skcipher_edesc *edesc = req_ctx->edesc;
++ int ecode = 0;
++ int ivsize = crypto_skcipher_ivsize(skcipher);
++
++#ifdef DEBUG
++ dev_err(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status);
++#endif
++
++ if (unlikely(status)) {
++ caam_qi2_strstatus(ctx->dev, status);
++ ecode = -EIO;
++ }
++
++#ifdef DEBUG
++ print_hex_dump(KERN_ERR, "dstiv @" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, req->iv,
++ edesc->src_nents > 1 ? 100 : ivsize, 1);
++ caam_dump_sg(KERN_ERR, "dst @" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, req->dst,
++ edesc->dst_nents > 1 ? 100 : req->cryptlen, 1);
++#endif
++
++ skcipher_unmap(ctx->dev, edesc, req);
++
++ /*
++ * The crypto API expects us to set the IV (req->iv) to the last
++ * ciphertext block. This is used e.g. by the CTS mode.
++ */
++ scatterwalk_map_and_copy(req->iv, req->dst, req->cryptlen - ivsize,
++ ivsize, 0);
++
++ qi_cache_free(edesc);
++ skcipher_request_complete(req, ecode);
++}
++
++static void skcipher_decrypt_done(void *cbk_ctx, u32 status)
++{
++ struct crypto_async_request *areq = cbk_ctx;
++ struct skcipher_request *req = skcipher_request_cast(areq);
++ struct caam_request *req_ctx = to_caam_req(areq);
++ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
++ struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
++ struct skcipher_edesc *edesc = req_ctx->edesc;
++ int ecode = 0;
++#ifdef DEBUG
++ int ivsize = crypto_skcipher_ivsize(skcipher);
++
++ dev_err(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status);
++#endif
++
++ if (unlikely(status)) {
++ caam_qi2_strstatus(ctx->dev, status);
++ ecode = -EIO;
++ }
++
++#ifdef DEBUG
++ print_hex_dump(KERN_ERR, "dstiv @" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, req->iv,
++ edesc->src_nents > 1 ? 100 : ivsize, 1);
++ caam_dump_sg(KERN_ERR, "dst @" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, req->dst,
++ edesc->dst_nents > 1 ? 100 : req->cryptlen, 1);
++#endif
++
++ skcipher_unmap(ctx->dev, edesc, req);
++ qi_cache_free(edesc);
++ skcipher_request_complete(req, ecode);
++}
++
++static int skcipher_encrypt(struct skcipher_request *req)
++{
++ struct skcipher_edesc *edesc;
++ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
++ struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
++ struct caam_request *caam_req = skcipher_request_ctx(req);
++ int ret;
++
++ /* allocate extended descriptor */
++ edesc = skcipher_edesc_alloc(req);
++ if (IS_ERR(edesc))
++ return PTR_ERR(edesc);
++
++ caam_req->flc = &ctx->flc[ENCRYPT];
++ caam_req->flc_dma = ctx->flc_dma[ENCRYPT];
++ caam_req->cbk = skcipher_encrypt_done;
++ caam_req->ctx = &req->base;
++ caam_req->edesc = edesc;
++ ret = dpaa2_caam_enqueue(ctx->dev, caam_req);
++ if (ret != -EINPROGRESS &&
++ !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
++ skcipher_unmap(ctx->dev, edesc, req);
++ qi_cache_free(edesc);
++ }
++
++ return ret;
++}
++
++static int skcipher_decrypt(struct skcipher_request *req)
++{
++ struct skcipher_edesc *edesc;
++ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
++ struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
++ struct caam_request *caam_req = skcipher_request_ctx(req);
++ int ivsize = crypto_skcipher_ivsize(skcipher);
++ int ret;
++
++ /* allocate extended descriptor */
++ edesc = skcipher_edesc_alloc(req);
++ if (IS_ERR(edesc))
++ return PTR_ERR(edesc);
++
++ /*
++ * The crypto API expects us to set the IV (req->iv) to the last
++ * ciphertext block.
++ */
++ scatterwalk_map_and_copy(req->iv, req->src, req->cryptlen - ivsize,
++ ivsize, 0);
++
++ caam_req->flc = &ctx->flc[DECRYPT];
++ caam_req->flc_dma = ctx->flc_dma[DECRYPT];
++ caam_req->cbk = skcipher_decrypt_done;
++ caam_req->ctx = &req->base;
++ caam_req->edesc = edesc;
++ ret = dpaa2_caam_enqueue(ctx->dev, caam_req);
++ if (ret != -EINPROGRESS &&
++ !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
++ skcipher_unmap(ctx->dev, edesc, req);
++ qi_cache_free(edesc);
++ }
++
++ return ret;
++}
++
++static int caam_cra_init(struct caam_ctx *ctx, struct caam_alg_entry *caam,
++ bool uses_dkp)
++{
++ dma_addr_t dma_addr;
++ int i;
++
++ /* copy descriptor header template value */
++ ctx->cdata.algtype = OP_TYPE_CLASS1_ALG | caam->class1_alg_type;
++ ctx->adata.algtype = OP_TYPE_CLASS2_ALG | caam->class2_alg_type;
++
++ ctx->dev = caam->dev;
++ ctx->dir = uses_dkp ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
++
++ dma_addr = dma_map_single_attrs(ctx->dev, ctx->flc,
++ offsetof(struct caam_ctx, flc_dma),
++ ctx->dir, DMA_ATTR_SKIP_CPU_SYNC);
++ if (dma_mapping_error(ctx->dev, dma_addr)) {
++ dev_err(ctx->dev, "unable to map key, shared descriptors\n");
++ return -ENOMEM;
++ }
++
++ for (i = 0; i < NUM_OP; i++)
++ ctx->flc_dma[i] = dma_addr + i * sizeof(ctx->flc[i]);
++ ctx->key_dma = dma_addr + NUM_OP * sizeof(ctx->flc[0]);
++
++ return 0;
++}
++
++static int caam_cra_init_skcipher(struct crypto_skcipher *tfm)
++{
++ struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
++ struct caam_skcipher_alg *caam_alg =
++ container_of(alg, typeof(*caam_alg), skcipher);
++
++ crypto_skcipher_set_reqsize(tfm, sizeof(struct caam_request));
++ return caam_cra_init(crypto_skcipher_ctx(tfm), &caam_alg->caam, false);
++}
++
++static int caam_cra_init_aead(struct crypto_aead *tfm)
++{
++ struct aead_alg *alg = crypto_aead_alg(tfm);
++ struct caam_aead_alg *caam_alg = container_of(alg, typeof(*caam_alg),
++ aead);
++
++ crypto_aead_set_reqsize(tfm, sizeof(struct caam_request));
++ return caam_cra_init(crypto_aead_ctx(tfm), &caam_alg->caam,
++ (alg->setkey == aead_setkey) ||
++ (alg->setkey == tls_setkey));
++}
++
++static void caam_exit_common(struct caam_ctx *ctx)
++{
++ dma_unmap_single_attrs(ctx->dev, ctx->flc_dma[0],
++ offsetof(struct caam_ctx, flc_dma), ctx->dir,
++ DMA_ATTR_SKIP_CPU_SYNC);
++}
++
++static void caam_cra_exit(struct crypto_skcipher *tfm)
++{
++ caam_exit_common(crypto_skcipher_ctx(tfm));
++}
++
++static void caam_cra_exit_aead(struct crypto_aead *tfm)
++{
++ caam_exit_common(crypto_aead_ctx(tfm));
++}
++
++static struct caam_skcipher_alg driver_algs[] = {
++ {
++ .skcipher = {
++ .base = {
++ .cra_name = "cbc(aes)",
++ .cra_driver_name = "cbc-aes-caam-qi2",
++ .cra_blocksize = AES_BLOCK_SIZE,
++ },
++ .setkey = skcipher_setkey,
++ .encrypt = skcipher_encrypt,
++ .decrypt = skcipher_decrypt,
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .ivsize = AES_BLOCK_SIZE,
++ },
++ .caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
++ },
++ {
++ .skcipher = {
++ .base = {
++ .cra_name = "cbc(des3_ede)",
++ .cra_driver_name = "cbc-3des-caam-qi2",
++ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
++ },
++ .setkey = skcipher_setkey,
++ .encrypt = skcipher_encrypt,
++ .decrypt = skcipher_decrypt,
++ .min_keysize = DES3_EDE_KEY_SIZE,
++ .max_keysize = DES3_EDE_KEY_SIZE,
++ .ivsize = DES3_EDE_BLOCK_SIZE,
++ },
++ .caam.class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
++ },
++ {
++ .skcipher = {
++ .base = {
++ .cra_name = "cbc(des)",
++ .cra_driver_name = "cbc-des-caam-qi2",
++ .cra_blocksize = DES_BLOCK_SIZE,
++ },
++ .setkey = skcipher_setkey,
++ .encrypt = skcipher_encrypt,
++ .decrypt = skcipher_decrypt,
++ .min_keysize = DES_KEY_SIZE,
++ .max_keysize = DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ },
++ .caam.class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
++ },
++ {
++ .skcipher = {
++ .base = {
++ .cra_name = "ctr(aes)",
++ .cra_driver_name = "ctr-aes-caam-qi2",
++ .cra_blocksize = 1,
++ },
++ .setkey = skcipher_setkey,
++ .encrypt = skcipher_encrypt,
++ .decrypt = skcipher_decrypt,
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .ivsize = AES_BLOCK_SIZE,
++ .chunksize = AES_BLOCK_SIZE,
++ },
++ .caam.class1_alg_type = OP_ALG_ALGSEL_AES |
++ OP_ALG_AAI_CTR_MOD128,
++ },
++ {
++ .skcipher = {
++ .base = {
++ .cra_name = "rfc3686(ctr(aes))",
++ .cra_driver_name = "rfc3686-ctr-aes-caam-qi2",
++ .cra_blocksize = 1,
++ },
++ .setkey = skcipher_setkey,
++ .encrypt = skcipher_encrypt,
++ .decrypt = skcipher_decrypt,
++ .min_keysize = AES_MIN_KEY_SIZE +
++ CTR_RFC3686_NONCE_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE +
++ CTR_RFC3686_NONCE_SIZE,
++ .ivsize = CTR_RFC3686_IV_SIZE,
++ .chunksize = AES_BLOCK_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES |
++ OP_ALG_AAI_CTR_MOD128,
++ .rfc3686 = true,
++ },
++ },
++ {
++ .skcipher = {
++ .base = {
++ .cra_name = "xts(aes)",
++ .cra_driver_name = "xts-aes-caam-qi2",
++ .cra_blocksize = AES_BLOCK_SIZE,
++ },
++ .setkey = xts_skcipher_setkey,
++ .encrypt = skcipher_encrypt,
++ .decrypt = skcipher_decrypt,
++ .min_keysize = 2 * AES_MIN_KEY_SIZE,
++ .max_keysize = 2 * AES_MAX_KEY_SIZE,
++ .ivsize = AES_BLOCK_SIZE,
++ },
++ .caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_XTS,
++ }
++};
++
++static struct caam_aead_alg driver_aeads[] = {
++ {
++ .aead = {
++ .base = {
++ .cra_name = "rfc4106(gcm(aes))",
++ .cra_driver_name = "rfc4106-gcm-aes-caam-qi2",
++ .cra_blocksize = 1,
++ },
++ .setkey = rfc4106_setkey,
++ .setauthsize = rfc4106_setauthsize,
++ .encrypt = ipsec_gcm_encrypt,
++ .decrypt = ipsec_gcm_decrypt,
++ .ivsize = 8,
++ .maxauthsize = AES_BLOCK_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
++ },
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "rfc4543(gcm(aes))",
++ .cra_driver_name = "rfc4543-gcm-aes-caam-qi2",
++ .cra_blocksize = 1,
++ },
++ .setkey = rfc4543_setkey,
++ .setauthsize = rfc4543_setauthsize,
++ .encrypt = ipsec_gcm_encrypt,
++ .decrypt = ipsec_gcm_decrypt,
++ .ivsize = 8,
++ .maxauthsize = AES_BLOCK_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
++ },
++ },
++ /* Galois Counter Mode */
++ {
++ .aead = {
++ .base = {
++ .cra_name = "gcm(aes)",
++ .cra_driver_name = "gcm-aes-caam-qi2",
++ .cra_blocksize = 1,
++ },
++ .setkey = gcm_setkey,
++ .setauthsize = gcm_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = 12,
++ .maxauthsize = AES_BLOCK_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
++ }
++ },
++ /* single-pass ipsec_esp descriptor */
++ {
++ .aead = {
++ .base = {
++ .cra_name = "authenc(hmac(md5),cbc(aes))",
++ .cra_driver_name = "authenc-hmac-md5-"
++ "cbc-aes-caam-qi2",
++ .cra_blocksize = AES_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = AES_BLOCK_SIZE,
++ .maxauthsize = MD5_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_MD5 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ }
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "echainiv(authenc(hmac(md5),"
++ "cbc(aes)))",
++ .cra_driver_name = "echainiv-authenc-hmac-md5-"
++ "cbc-aes-caam-qi2",
++ .cra_blocksize = AES_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = AES_BLOCK_SIZE,
++ .maxauthsize = MD5_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_MD5 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .geniv = true,
++ }
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "authenc(hmac(sha1),cbc(aes))",
++ .cra_driver_name = "authenc-hmac-sha1-"
++ "cbc-aes-caam-qi2",
++ .cra_blocksize = AES_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = AES_BLOCK_SIZE,
++ .maxauthsize = SHA1_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA1 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ }
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "echainiv(authenc(hmac(sha1),"
++ "cbc(aes)))",
++ .cra_driver_name = "echainiv-authenc-"
++ "hmac-sha1-cbc-aes-caam-qi2",
++ .cra_blocksize = AES_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = AES_BLOCK_SIZE,
++ .maxauthsize = SHA1_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA1 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .geniv = true,
++ },
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "authenc(hmac(sha224),cbc(aes))",
++ .cra_driver_name = "authenc-hmac-sha224-"
++ "cbc-aes-caam-qi2",
++ .cra_blocksize = AES_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = AES_BLOCK_SIZE,
++ .maxauthsize = SHA224_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA224 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ }
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "echainiv(authenc(hmac(sha224),"
++ "cbc(aes)))",
++ .cra_driver_name = "echainiv-authenc-"
++ "hmac-sha224-cbc-aes-caam-qi2",
++ .cra_blocksize = AES_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = AES_BLOCK_SIZE,
++ .maxauthsize = SHA224_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA224 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .geniv = true,
++ }
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "authenc(hmac(sha256),cbc(aes))",
++ .cra_driver_name = "authenc-hmac-sha256-"
++ "cbc-aes-caam-qi2",
++ .cra_blocksize = AES_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = AES_BLOCK_SIZE,
++ .maxauthsize = SHA256_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA256 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ }
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "echainiv(authenc(hmac(sha256),"
++ "cbc(aes)))",
++ .cra_driver_name = "echainiv-authenc-"
++ "hmac-sha256-cbc-aes-"
++ "caam-qi2",
++ .cra_blocksize = AES_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = AES_BLOCK_SIZE,
++ .maxauthsize = SHA256_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA256 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .geniv = true,
++ }
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "authenc(hmac(sha384),cbc(aes))",
++ .cra_driver_name = "authenc-hmac-sha384-"
++ "cbc-aes-caam-qi2",
++ .cra_blocksize = AES_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = AES_BLOCK_SIZE,
++ .maxauthsize = SHA384_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA384 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ }
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "echainiv(authenc(hmac(sha384),"
++ "cbc(aes)))",
++ .cra_driver_name = "echainiv-authenc-"
++ "hmac-sha384-cbc-aes-"
++ "caam-qi2",
++ .cra_blocksize = AES_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = AES_BLOCK_SIZE,
++ .maxauthsize = SHA384_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA384 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .geniv = true,
++ }
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "authenc(hmac(sha512),cbc(aes))",
++ .cra_driver_name = "authenc-hmac-sha512-"
++ "cbc-aes-caam-qi2",
++ .cra_blocksize = AES_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = AES_BLOCK_SIZE,
++ .maxauthsize = SHA512_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA512 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ }
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "echainiv(authenc(hmac(sha512),"
++ "cbc(aes)))",
++ .cra_driver_name = "echainiv-authenc-"
++ "hmac-sha512-cbc-aes-"
++ "caam-qi2",
++ .cra_blocksize = AES_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = AES_BLOCK_SIZE,
++ .maxauthsize = SHA512_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA512 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .geniv = true,
++ }
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "authenc(hmac(md5),cbc(des3_ede))",
++ .cra_driver_name = "authenc-hmac-md5-"
++ "cbc-des3_ede-caam-qi2",
++ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = DES3_EDE_BLOCK_SIZE,
++ .maxauthsize = MD5_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_MD5 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ }
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "echainiv(authenc(hmac(md5),"
++ "cbc(des3_ede)))",
++ .cra_driver_name = "echainiv-authenc-hmac-md5-"
++ "cbc-des3_ede-caam-qi2",
++ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = DES3_EDE_BLOCK_SIZE,
++ .maxauthsize = MD5_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_MD5 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .geniv = true,
++ }
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "authenc(hmac(sha1),"
++ "cbc(des3_ede))",
++ .cra_driver_name = "authenc-hmac-sha1-"
++ "cbc-des3_ede-caam-qi2",
++ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = DES3_EDE_BLOCK_SIZE,
++ .maxauthsize = SHA1_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA1 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ },
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "echainiv(authenc(hmac(sha1),"
++ "cbc(des3_ede)))",
++ .cra_driver_name = "echainiv-authenc-"
++ "hmac-sha1-"
++ "cbc-des3_ede-caam-qi2",
++ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = DES3_EDE_BLOCK_SIZE,
++ .maxauthsize = SHA1_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA1 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .geniv = true,
++ }
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "authenc(hmac(sha224),"
++ "cbc(des3_ede))",
++ .cra_driver_name = "authenc-hmac-sha224-"
++ "cbc-des3_ede-caam-qi2",
++ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = DES3_EDE_BLOCK_SIZE,
++ .maxauthsize = SHA224_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA224 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ },
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "echainiv(authenc(hmac(sha224),"
++ "cbc(des3_ede)))",
++ .cra_driver_name = "echainiv-authenc-"
++ "hmac-sha224-"
++ "cbc-des3_ede-caam-qi2",
++ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = DES3_EDE_BLOCK_SIZE,
++ .maxauthsize = SHA224_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA224 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .geniv = true,
++ }
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "authenc(hmac(sha256),"
++ "cbc(des3_ede))",
++ .cra_driver_name = "authenc-hmac-sha256-"
++ "cbc-des3_ede-caam-qi2",
++ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = DES3_EDE_BLOCK_SIZE,
++ .maxauthsize = SHA256_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA256 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ },
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "echainiv(authenc(hmac(sha256),"
++ "cbc(des3_ede)))",
++ .cra_driver_name = "echainiv-authenc-"
++ "hmac-sha256-"
++ "cbc-des3_ede-caam-qi2",
++ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = DES3_EDE_BLOCK_SIZE,
++ .maxauthsize = SHA256_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA256 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .geniv = true,
++ }
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "authenc(hmac(sha384),"
++ "cbc(des3_ede))",
++ .cra_driver_name = "authenc-hmac-sha384-"
++ "cbc-des3_ede-caam-qi2",
++ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = DES3_EDE_BLOCK_SIZE,
++ .maxauthsize = SHA384_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA384 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ },
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "echainiv(authenc(hmac(sha384),"
++ "cbc(des3_ede)))",
++ .cra_driver_name = "echainiv-authenc-"
++ "hmac-sha384-"
++ "cbc-des3_ede-caam-qi2",
++ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = DES3_EDE_BLOCK_SIZE,
++ .maxauthsize = SHA384_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA384 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .geniv = true,
++ }
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "authenc(hmac(sha512),"
++ "cbc(des3_ede))",
++ .cra_driver_name = "authenc-hmac-sha512-"
++ "cbc-des3_ede-caam-qi2",
++ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = DES3_EDE_BLOCK_SIZE,
++ .maxauthsize = SHA512_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA512 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ },
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "echainiv(authenc(hmac(sha512),"
++ "cbc(des3_ede)))",
++ .cra_driver_name = "echainiv-authenc-"
++ "hmac-sha512-"
++ "cbc-des3_ede-caam-qi2",
++ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = DES3_EDE_BLOCK_SIZE,
++ .maxauthsize = SHA512_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA512 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .geniv = true,
++ }
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "authenc(hmac(md5),cbc(des))",
++ .cra_driver_name = "authenc-hmac-md5-"
++ "cbc-des-caam-qi2",
++ .cra_blocksize = DES_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = DES_BLOCK_SIZE,
++ .maxauthsize = MD5_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_MD5 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ },
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "echainiv(authenc(hmac(md5),"
++ "cbc(des)))",
++ .cra_driver_name = "echainiv-authenc-hmac-md5-"
++ "cbc-des-caam-qi2",
++ .cra_blocksize = DES_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = DES_BLOCK_SIZE,
++ .maxauthsize = MD5_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_MD5 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .geniv = true,
++ }
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "authenc(hmac(sha1),cbc(des))",
++ .cra_driver_name = "authenc-hmac-sha1-"
++ "cbc-des-caam-qi2",
++ .cra_blocksize = DES_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = DES_BLOCK_SIZE,
++ .maxauthsize = SHA1_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA1 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ },
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "echainiv(authenc(hmac(sha1),"
++ "cbc(des)))",
++ .cra_driver_name = "echainiv-authenc-"
++ "hmac-sha1-cbc-des-caam-qi2",
++ .cra_blocksize = DES_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = DES_BLOCK_SIZE,
++ .maxauthsize = SHA1_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA1 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .geniv = true,
++ }
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "authenc(hmac(sha224),cbc(des))",
++ .cra_driver_name = "authenc-hmac-sha224-"
++ "cbc-des-caam-qi2",
++ .cra_blocksize = DES_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = DES_BLOCK_SIZE,
++ .maxauthsize = SHA224_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA224 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ },
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "echainiv(authenc(hmac(sha224),"
++ "cbc(des)))",
++ .cra_driver_name = "echainiv-authenc-"
++ "hmac-sha224-cbc-des-"
++ "caam-qi2",
++ .cra_blocksize = DES_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = DES_BLOCK_SIZE,
++ .maxauthsize = SHA224_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA224 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .geniv = true,
++ }
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "authenc(hmac(sha256),cbc(des))",
++ .cra_driver_name = "authenc-hmac-sha256-"
++ "cbc-des-caam-qi2",
++ .cra_blocksize = DES_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = DES_BLOCK_SIZE,
++ .maxauthsize = SHA256_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA256 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ },
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "echainiv(authenc(hmac(sha256),"
++ "cbc(des)))",
++ .cra_driver_name = "echainiv-authenc-"
++ "hmac-sha256-cbc-desi-"
++ "caam-qi2",
++ .cra_blocksize = DES_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = DES_BLOCK_SIZE,
++ .maxauthsize = SHA256_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA256 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .geniv = true,
++ },
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "authenc(hmac(sha384),cbc(des))",
++ .cra_driver_name = "authenc-hmac-sha384-"
++ "cbc-des-caam-qi2",
++ .cra_blocksize = DES_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = DES_BLOCK_SIZE,
++ .maxauthsize = SHA384_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA384 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ },
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "echainiv(authenc(hmac(sha384),"
++ "cbc(des)))",
++ .cra_driver_name = "echainiv-authenc-"
++ "hmac-sha384-cbc-des-"
++ "caam-qi2",
++ .cra_blocksize = DES_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = DES_BLOCK_SIZE,
++ .maxauthsize = SHA384_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA384 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .geniv = true,
++ }
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "authenc(hmac(sha512),cbc(des))",
++ .cra_driver_name = "authenc-hmac-sha512-"
++ "cbc-des-caam-qi2",
++ .cra_blocksize = DES_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = DES_BLOCK_SIZE,
++ .maxauthsize = SHA512_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA512 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ }
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "echainiv(authenc(hmac(sha512),"
++ "cbc(des)))",
++ .cra_driver_name = "echainiv-authenc-"
++ "hmac-sha512-cbc-des-"
++ "caam-qi2",
++ .cra_blocksize = DES_BLOCK_SIZE,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = DES_BLOCK_SIZE,
++ .maxauthsize = SHA512_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA512 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .geniv = true,
++ }
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "authenc(hmac(md5),"
++ "rfc3686(ctr(aes)))",
++ .cra_driver_name = "authenc-hmac-md5-"
++ "rfc3686-ctr-aes-caam-qi2",
++ .cra_blocksize = 1,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = CTR_RFC3686_IV_SIZE,
++ .maxauthsize = MD5_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES |
++ OP_ALG_AAI_CTR_MOD128,
++ .class2_alg_type = OP_ALG_ALGSEL_MD5 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .rfc3686 = true,
++ },
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "seqiv(authenc("
++ "hmac(md5),rfc3686(ctr(aes))))",
++ .cra_driver_name = "seqiv-authenc-hmac-md5-"
++ "rfc3686-ctr-aes-caam-qi2",
++ .cra_blocksize = 1,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = CTR_RFC3686_IV_SIZE,
++ .maxauthsize = MD5_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES |
++ OP_ALG_AAI_CTR_MOD128,
++ .class2_alg_type = OP_ALG_ALGSEL_MD5 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .rfc3686 = true,
++ .geniv = true,
++ },
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "authenc(hmac(sha1),"
++ "rfc3686(ctr(aes)))",
++ .cra_driver_name = "authenc-hmac-sha1-"
++ "rfc3686-ctr-aes-caam-qi2",
++ .cra_blocksize = 1,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = CTR_RFC3686_IV_SIZE,
++ .maxauthsize = SHA1_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES |
++ OP_ALG_AAI_CTR_MOD128,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA1 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .rfc3686 = true,
++ },
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "seqiv(authenc("
++ "hmac(sha1),rfc3686(ctr(aes))))",
++ .cra_driver_name = "seqiv-authenc-hmac-sha1-"
++ "rfc3686-ctr-aes-caam-qi2",
++ .cra_blocksize = 1,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = CTR_RFC3686_IV_SIZE,
++ .maxauthsize = SHA1_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES |
++ OP_ALG_AAI_CTR_MOD128,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA1 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .rfc3686 = true,
++ .geniv = true,
++ },
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "authenc(hmac(sha224),"
++ "rfc3686(ctr(aes)))",
++ .cra_driver_name = "authenc-hmac-sha224-"
++ "rfc3686-ctr-aes-caam-qi2",
++ .cra_blocksize = 1,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = CTR_RFC3686_IV_SIZE,
++ .maxauthsize = SHA224_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES |
++ OP_ALG_AAI_CTR_MOD128,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA224 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .rfc3686 = true,
++ },
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "seqiv(authenc("
++ "hmac(sha224),rfc3686(ctr(aes))))",
++ .cra_driver_name = "seqiv-authenc-hmac-sha224-"
++ "rfc3686-ctr-aes-caam-qi2",
++ .cra_blocksize = 1,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = CTR_RFC3686_IV_SIZE,
++ .maxauthsize = SHA224_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES |
++ OP_ALG_AAI_CTR_MOD128,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA224 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .rfc3686 = true,
++ .geniv = true,
++ },
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "authenc(hmac(sha256),"
++ "rfc3686(ctr(aes)))",
++ .cra_driver_name = "authenc-hmac-sha256-"
++ "rfc3686-ctr-aes-caam-qi2",
++ .cra_blocksize = 1,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = CTR_RFC3686_IV_SIZE,
++ .maxauthsize = SHA256_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES |
++ OP_ALG_AAI_CTR_MOD128,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA256 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .rfc3686 = true,
++ },
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "seqiv(authenc(hmac(sha256),"
++ "rfc3686(ctr(aes))))",
++ .cra_driver_name = "seqiv-authenc-hmac-sha256-"
++ "rfc3686-ctr-aes-caam-qi2",
++ .cra_blocksize = 1,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = CTR_RFC3686_IV_SIZE,
++ .maxauthsize = SHA256_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES |
++ OP_ALG_AAI_CTR_MOD128,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA256 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .rfc3686 = true,
++ .geniv = true,
++ },
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "authenc(hmac(sha384),"
++ "rfc3686(ctr(aes)))",
++ .cra_driver_name = "authenc-hmac-sha384-"
++ "rfc3686-ctr-aes-caam-qi2",
++ .cra_blocksize = 1,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = CTR_RFC3686_IV_SIZE,
++ .maxauthsize = SHA384_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES |
++ OP_ALG_AAI_CTR_MOD128,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA384 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .rfc3686 = true,
++ },
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "seqiv(authenc(hmac(sha384),"
++ "rfc3686(ctr(aes))))",
++ .cra_driver_name = "seqiv-authenc-hmac-sha384-"
++ "rfc3686-ctr-aes-caam-qi2",
++ .cra_blocksize = 1,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = CTR_RFC3686_IV_SIZE,
++ .maxauthsize = SHA384_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES |
++ OP_ALG_AAI_CTR_MOD128,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA384 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .rfc3686 = true,
++ .geniv = true,
++ },
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "authenc(hmac(sha512),"
++ "rfc3686(ctr(aes)))",
++ .cra_driver_name = "authenc-hmac-sha512-"
++ "rfc3686-ctr-aes-caam-qi2",
++ .cra_blocksize = 1,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = CTR_RFC3686_IV_SIZE,
++ .maxauthsize = SHA512_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES |
++ OP_ALG_AAI_CTR_MOD128,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA512 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .rfc3686 = true,
++ },
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "seqiv(authenc(hmac(sha512),"
++ "rfc3686(ctr(aes))))",
++ .cra_driver_name = "seqiv-authenc-hmac-sha512-"
++ "rfc3686-ctr-aes-caam-qi2",
++ .cra_blocksize = 1,
++ },
++ .setkey = aead_setkey,
++ .setauthsize = aead_setauthsize,
++ .encrypt = aead_encrypt,
++ .decrypt = aead_decrypt,
++ .ivsize = CTR_RFC3686_IV_SIZE,
++ .maxauthsize = SHA512_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES |
++ OP_ALG_AAI_CTR_MOD128,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA512 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ .rfc3686 = true,
++ .geniv = true,
++ },
++ },
++ {
++ .aead = {
++ .base = {
++ .cra_name = "tls10(hmac(sha1),cbc(aes))",
++ .cra_driver_name = "tls10-hmac-sha1-cbc-aes-caam-qi2",
++ .cra_blocksize = AES_BLOCK_SIZE,
++ },
++ .setkey = tls_setkey,
++ .setauthsize = tls_setauthsize,
++ .encrypt = tls_encrypt,
++ .decrypt = tls_decrypt,
++ .ivsize = AES_BLOCK_SIZE,
++ .maxauthsize = SHA1_DIGEST_SIZE,
++ },
++ .caam = {
++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
++ .class2_alg_type = OP_ALG_ALGSEL_SHA1 |
++ OP_ALG_AAI_HMAC_PRECOMP,
++ },
++ },
++};
++
++static void caam_skcipher_alg_init(struct caam_skcipher_alg *t_alg)
++{
++ struct skcipher_alg *alg = &t_alg->skcipher;
++
++ alg->base.cra_module = THIS_MODULE;
++ alg->base.cra_priority = CAAM_CRA_PRIORITY;
++ alg->base.cra_ctxsize = sizeof(struct caam_ctx);
++ alg->base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY;
++
++ alg->init = caam_cra_init_skcipher;
++ alg->exit = caam_cra_exit;
++}
++
++static void caam_aead_alg_init(struct caam_aead_alg *t_alg)
++{
++ struct aead_alg *alg = &t_alg->aead;
++
++ alg->base.cra_module = THIS_MODULE;
++ alg->base.cra_priority = CAAM_CRA_PRIORITY;
++ alg->base.cra_ctxsize = sizeof(struct caam_ctx);
++ alg->base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY;
++
++ alg->init = caam_cra_init_aead;
++ alg->exit = caam_cra_exit_aead;
++}
++
++/* max hash key is max split key size */
++#define CAAM_MAX_HASH_KEY_SIZE (SHA512_DIGEST_SIZE * 2)
++
++#define CAAM_MAX_HASH_BLOCK_SIZE SHA512_BLOCK_SIZE
++#define CAAM_MAX_HASH_DIGEST_SIZE SHA512_DIGEST_SIZE
++
++#define DESC_HASH_MAX_USED_BYTES (DESC_AHASH_FINAL_LEN + \
++ CAAM_MAX_HASH_KEY_SIZE)
++#define DESC_HASH_MAX_USED_LEN (DESC_HASH_MAX_USED_BYTES / CAAM_CMD_SZ)
++
++/* caam context sizes for hashes: running digest + 8 */
++#define HASH_MSG_LEN 8
++#define MAX_CTX_LEN (HASH_MSG_LEN + SHA512_DIGEST_SIZE)
++
++enum hash_optype {
++ UPDATE = 0,
++ UPDATE_FIRST,
++ FINALIZE,
++ DIGEST,
++ HASH_NUM_OP
++};
++
++/**
++ * caam_hash_ctx - ahash per-session context
++ * @flc: Flow Contexts array
++ * @flc_dma: I/O virtual addresses of the Flow Contexts
++ * @key: virtual address of the authentication key
++ * @dev: dpseci device
++ * @ctx_len: size of Context Register
++ * @adata: hashing algorithm details
++ */
++struct caam_hash_ctx {
++ struct caam_flc flc[HASH_NUM_OP];
++ dma_addr_t flc_dma[HASH_NUM_OP];
++ u8 key[CAAM_MAX_HASH_KEY_SIZE];
++ struct device *dev;
++ int ctx_len;
++ struct alginfo adata;
++};
++
++/* ahash state */
++struct caam_hash_state {
++ struct caam_request caam_req;
++ dma_addr_t buf_dma;
++ dma_addr_t ctx_dma;
++ u8 buf_0[CAAM_MAX_HASH_BLOCK_SIZE] ____cacheline_aligned;
++ int buflen_0;
++ u8 buf_1[CAAM_MAX_HASH_BLOCK_SIZE] ____cacheline_aligned;
++ int buflen_1;
++ u8 caam_ctx[MAX_CTX_LEN] ____cacheline_aligned;
++ int (*update)(struct ahash_request *req);
++ int (*final)(struct ahash_request *req);
++ int (*finup)(struct ahash_request *req);
++ int current_buf;
++};
++
++struct caam_export_state {
++ u8 buf[CAAM_MAX_HASH_BLOCK_SIZE];
++ u8 caam_ctx[MAX_CTX_LEN];
++ int buflen;
++ int (*update)(struct ahash_request *req);
++ int (*final)(struct ahash_request *req);
++ int (*finup)(struct ahash_request *req);
++};
++
++static inline void switch_buf(struct caam_hash_state *state)
++{
++ state->current_buf ^= 1;
++}
++
++static inline u8 *current_buf(struct caam_hash_state *state)
++{
++ return state->current_buf ? state->buf_1 : state->buf_0;
++}
++
++static inline u8 *alt_buf(struct caam_hash_state *state)
++{
++ return state->current_buf ? state->buf_0 : state->buf_1;
++}
++
++static inline int *current_buflen(struct caam_hash_state *state)
++{
++ return state->current_buf ? &state->buflen_1 : &state->buflen_0;
++}
++
++static inline int *alt_buflen(struct caam_hash_state *state)
++{
++ return state->current_buf ? &state->buflen_0 : &state->buflen_1;
++}
++
++/* Map current buffer in state (if length > 0) and put it in link table */
++static inline int buf_map_to_qm_sg(struct device *dev,
++ struct dpaa2_sg_entry *qm_sg,
++ struct caam_hash_state *state)
++{
++ int buflen = *current_buflen(state);
++
++ if (!buflen)
++ return 0;
++
++ state->buf_dma = dma_map_single(dev, current_buf(state), buflen,
++ DMA_TO_DEVICE);
++ if (dma_mapping_error(dev, state->buf_dma)) {
++ dev_err(dev, "unable to map buf\n");
++ state->buf_dma = 0;
++ return -ENOMEM;
++ }
++
++ dma_to_qm_sg_one(qm_sg, state->buf_dma, buflen, 0);
++
++ return 0;
++}
++
++/* Map state->caam_ctx, and add it to link table */
++static inline int ctx_map_to_qm_sg(struct device *dev,
++ struct caam_hash_state *state, int ctx_len,
++ struct dpaa2_sg_entry *qm_sg, u32 flag)
++{
++ state->ctx_dma = dma_map_single(dev, state->caam_ctx, ctx_len, flag);
++ if (dma_mapping_error(dev, state->ctx_dma)) {
++ dev_err(dev, "unable to map ctx\n");
++ state->ctx_dma = 0;
++ return -ENOMEM;
++ }
++
++ dma_to_qm_sg_one(qm_sg, state->ctx_dma, ctx_len, 0);
++
++ return 0;
++}
++
++static int ahash_set_sh_desc(struct crypto_ahash *ahash)
++{
++ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
++ int digestsize = crypto_ahash_digestsize(ahash);
++ struct dpaa2_caam_priv *priv = dev_get_drvdata(ctx->dev);
++ struct caam_flc *flc;
++ u32 *desc;
++
++ ctx->adata.key_virt = ctx->key;
++ ctx->adata.key_inline = true;
++
++ /* ahash_update shared descriptor */
++ flc = &ctx->flc[UPDATE];
++ desc = flc->sh_desc;
++ cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_UPDATE, ctx->ctx_len,
++ ctx->ctx_len, true, priv->sec_attr.era);
++ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
++ dma_sync_single_for_device(ctx->dev, ctx->flc_dma[UPDATE],
++ desc_bytes(desc), DMA_BIDIRECTIONAL);
++#ifdef DEBUG
++ print_hex_dump(KERN_ERR,
++ "ahash update shdesc@" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
++#endif
++
++ /* ahash_update_first shared descriptor */
++ flc = &ctx->flc[UPDATE_FIRST];
++ desc = flc->sh_desc;
++ cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_INIT, ctx->ctx_len,
++ ctx->ctx_len, false, priv->sec_attr.era);
++ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
++ dma_sync_single_for_device(ctx->dev, ctx->flc_dma[UPDATE_FIRST],
++ desc_bytes(desc), DMA_BIDIRECTIONAL);
++#ifdef DEBUG
++ print_hex_dump(KERN_ERR,
++ "ahash update first shdesc@" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
++#endif
++
++ /* ahash_final shared descriptor */
++ flc = &ctx->flc[FINALIZE];
++ desc = flc->sh_desc;
++ cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_FINALIZE, digestsize,
++ ctx->ctx_len, true, priv->sec_attr.era);
++ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
++ dma_sync_single_for_device(ctx->dev, ctx->flc_dma[FINALIZE],
++ desc_bytes(desc), DMA_BIDIRECTIONAL);
++#ifdef DEBUG
++ print_hex_dump(KERN_ERR,
++ "ahash final shdesc@" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
++#endif
++
++ /* ahash_digest shared descriptor */
++ flc = &ctx->flc[DIGEST];
++ desc = flc->sh_desc;
++ cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_INITFINAL, digestsize,
++ ctx->ctx_len, false, priv->sec_attr.era);
++ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
++ dma_sync_single_for_device(ctx->dev, ctx->flc_dma[DIGEST],
++ desc_bytes(desc), DMA_BIDIRECTIONAL);
++#ifdef DEBUG
++ print_hex_dump(KERN_ERR,
++ "ahash digest shdesc@" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
++#endif
++
++ return 0;
++}
++
++/* Digest hash size if it is too large */
++static int hash_digest_key(struct caam_hash_ctx *ctx, const u8 *key_in,
++ u32 *keylen, u8 *key_out, u32 digestsize)
++{
++ struct caam_request *req_ctx;
++ u32 *desc;
++ struct split_key_sh_result result;
++ dma_addr_t src_dma, dst_dma;
++ struct caam_flc *flc;
++ dma_addr_t flc_dma;
++ int ret = -ENOMEM;
++ struct dpaa2_fl_entry *in_fle, *out_fle;
++
++ req_ctx = kzalloc(sizeof(*req_ctx), GFP_KERNEL | GFP_DMA);
++ if (!req_ctx)
++ return -ENOMEM;
++
++ in_fle = &req_ctx->fd_flt[1];
++ out_fle = &req_ctx->fd_flt[0];
++
++ flc = kzalloc(sizeof(*flc), GFP_KERNEL | GFP_DMA);
++ if (!flc)
++ goto err_flc;
++
++ src_dma = dma_map_single(ctx->dev, (void *)key_in, *keylen,
++ DMA_TO_DEVICE);
++ if (dma_mapping_error(ctx->dev, src_dma)) {
++ dev_err(ctx->dev, "unable to map key input memory\n");
++ goto err_src_dma;
++ }
++ dst_dma = dma_map_single(ctx->dev, (void *)key_out, digestsize,
++ DMA_FROM_DEVICE);
++ if (dma_mapping_error(ctx->dev, dst_dma)) {
++ dev_err(ctx->dev, "unable to map key output memory\n");
++ goto err_dst_dma;
++ }
++
++ desc = flc->sh_desc;
++
++ init_sh_desc(desc, 0);
++
++ /* descriptor to perform unkeyed hash on key_in */
++ append_operation(desc, ctx->adata.algtype | OP_ALG_ENCRYPT |
++ OP_ALG_AS_INITFINAL);
++ append_seq_fifo_load(desc, *keylen, FIFOLD_CLASS_CLASS2 |
++ FIFOLD_TYPE_LAST2 | FIFOLD_TYPE_MSG);
++ append_seq_store(desc, digestsize, LDST_CLASS_2_CCB |
++ LDST_SRCDST_BYTE_CONTEXT);
++
++ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
++ flc_dma = dma_map_single(ctx->dev, flc, sizeof(flc->flc) +
++ desc_bytes(desc), DMA_TO_DEVICE);
++ if (dma_mapping_error(ctx->dev, flc_dma)) {
++ dev_err(ctx->dev, "unable to map shared descriptor\n");
++ goto err_flc_dma;
++ }
++
++ dpaa2_fl_set_final(in_fle, true);
++ dpaa2_fl_set_format(in_fle, dpaa2_fl_single);
++ dpaa2_fl_set_addr(in_fle, src_dma);
++ dpaa2_fl_set_len(in_fle, *keylen);
++ dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
++ dpaa2_fl_set_addr(out_fle, dst_dma);
++ dpaa2_fl_set_len(out_fle, digestsize);
++
++#ifdef DEBUG
++ print_hex_dump(KERN_ERR, "key_in@" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, key_in, *keylen, 1);
++ print_hex_dump(KERN_ERR, "shdesc@" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
++#endif
++
++ result.err = 0;
++ init_completion(&result.completion);
++ result.dev = ctx->dev;
++
++ req_ctx->flc = flc;
++ req_ctx->flc_dma = flc_dma;
++ req_ctx->cbk = split_key_sh_done;
++ req_ctx->ctx = &result;
++
++ ret = dpaa2_caam_enqueue(ctx->dev, req_ctx);
++ if (ret == -EINPROGRESS) {
++ /* in progress */
++ wait_for_completion(&result.completion);
++ ret = result.err;
++#ifdef DEBUG
++ print_hex_dump(KERN_ERR,
++ "digested key@" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, key_in, digestsize,
++ 1);
++#endif
++ }
++
++ dma_unmap_single(ctx->dev, flc_dma, sizeof(flc->flc) + desc_bytes(desc),
++ DMA_TO_DEVICE);
++err_flc_dma:
++ dma_unmap_single(ctx->dev, dst_dma, digestsize, DMA_FROM_DEVICE);
++err_dst_dma:
++ dma_unmap_single(ctx->dev, src_dma, *keylen, DMA_TO_DEVICE);
++err_src_dma:
++ kfree(flc);
++err_flc:
++ kfree(req_ctx);
++
++ *keylen = digestsize;
++
++ return ret;
++}
++
++static int ahash_setkey(struct crypto_ahash *ahash, const u8 *key,
++ unsigned int keylen)
++{
++ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
++ unsigned int blocksize = crypto_tfm_alg_blocksize(&ahash->base);
++ unsigned int digestsize = crypto_ahash_digestsize(ahash);
++ int ret;
++ u8 *hashed_key = NULL;
++
++#ifdef DEBUG
++ dev_err(ctx->dev, "keylen %d blocksize %d\n", keylen, blocksize);
++#endif
++
++ if (keylen > blocksize) {
++ hashed_key = kmalloc_array(digestsize, sizeof(*hashed_key),
++ GFP_KERNEL | GFP_DMA);
++ if (!hashed_key)
++ return -ENOMEM;
++ ret = hash_digest_key(ctx, key, &keylen, hashed_key,
++ digestsize);
++ if (ret)
++ goto bad_free_key;
++ key = hashed_key;
++ }
++
++ ctx->adata.keylen = keylen;
++ ctx->adata.keylen_pad = split_key_len(ctx->adata.algtype &
++ OP_ALG_ALGSEL_MASK);
++ if (ctx->adata.keylen_pad > CAAM_MAX_HASH_KEY_SIZE)
++ goto bad_free_key;
++
++ memcpy(ctx->key, key, keylen);
++
++ kfree(hashed_key);
++ return ahash_set_sh_desc(ahash);
++bad_free_key:
++ kfree(hashed_key);
++ crypto_ahash_set_flags(ahash, CRYPTO_TFM_RES_BAD_KEY_LEN);
++ return -EINVAL;
++}
++
++static inline void ahash_unmap(struct device *dev, struct ahash_edesc *edesc,
++ struct ahash_request *req, int dst_len)
++{
++ struct caam_hash_state *state = ahash_request_ctx(req);
++
++ if (edesc->src_nents)
++ dma_unmap_sg(dev, req->src, edesc->src_nents, DMA_TO_DEVICE);
++ if (edesc->dst_dma)
++ dma_unmap_single(dev, edesc->dst_dma, dst_len, DMA_FROM_DEVICE);
++
++ if (edesc->qm_sg_bytes)
++ dma_unmap_single(dev, edesc->qm_sg_dma, edesc->qm_sg_bytes,
++ DMA_TO_DEVICE);
++
++ if (state->buf_dma) {
++ dma_unmap_single(dev, state->buf_dma, *current_buflen(state),
++ DMA_TO_DEVICE);
++ state->buf_dma = 0;
++ }
++}
++
++static inline void ahash_unmap_ctx(struct device *dev,
++ struct ahash_edesc *edesc,
++ struct ahash_request *req, int dst_len,
++ u32 flag)
++{
++ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
++ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
++ struct caam_hash_state *state = ahash_request_ctx(req);
++
++ if (state->ctx_dma) {
++ dma_unmap_single(dev, state->ctx_dma, ctx->ctx_len, flag);
++ state->ctx_dma = 0;
++ }
++ ahash_unmap(dev, edesc, req, dst_len);
++}
++
++static void ahash_done(void *cbk_ctx, u32 status)
++{
++ struct crypto_async_request *areq = cbk_ctx;
++ struct ahash_request *req = ahash_request_cast(areq);
++ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
++ struct caam_hash_state *state = ahash_request_ctx(req);
++ struct ahash_edesc *edesc = state->caam_req.edesc;
++ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
++ int digestsize = crypto_ahash_digestsize(ahash);
++ int ecode = 0;
++
++#ifdef DEBUG
++ dev_err(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status);
++#endif
++
++ if (unlikely(status)) {
++ caam_qi2_strstatus(ctx->dev, status);
++ ecode = -EIO;
++ }
++
++ ahash_unmap(ctx->dev, edesc, req, digestsize);
++ qi_cache_free(edesc);
++
++#ifdef DEBUG
++ print_hex_dump(KERN_ERR, "ctx@" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx,
++ ctx->ctx_len, 1);
++ if (req->result)
++ print_hex_dump(KERN_ERR, "result@" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, req->result,
++ digestsize, 1);
++#endif
++
++ req->base.complete(&req->base, ecode);
++}
++
++static void ahash_done_bi(void *cbk_ctx, u32 status)
++{
++ struct crypto_async_request *areq = cbk_ctx;
++ struct ahash_request *req = ahash_request_cast(areq);
++ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
++ struct caam_hash_state *state = ahash_request_ctx(req);
++ struct ahash_edesc *edesc = state->caam_req.edesc;
++ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
++ int ecode = 0;
++#ifdef DEBUG
++ int digestsize = crypto_ahash_digestsize(ahash);
++
++ dev_err(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status);
++#endif
++
++ if (unlikely(status)) {
++ caam_qi2_strstatus(ctx->dev, status);
++ ecode = -EIO;
++ }
++
++ ahash_unmap_ctx(ctx->dev, edesc, req, ctx->ctx_len, DMA_BIDIRECTIONAL);
++ switch_buf(state);
++ qi_cache_free(edesc);
++
++#ifdef DEBUG
++ print_hex_dump(KERN_ERR, "ctx@" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx,
++ ctx->ctx_len, 1);
++ if (req->result)
++ print_hex_dump(KERN_ERR, "result@" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, req->result,
++ digestsize, 1);
++#endif
++
++ req->base.complete(&req->base, ecode);
++}
++
++static void ahash_done_ctx_src(void *cbk_ctx, u32 status)
++{
++ struct crypto_async_request *areq = cbk_ctx;
++ struct ahash_request *req = ahash_request_cast(areq);
++ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
++ struct caam_hash_state *state = ahash_request_ctx(req);
++ struct ahash_edesc *edesc = state->caam_req.edesc;
++ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
++ int digestsize = crypto_ahash_digestsize(ahash);
++ int ecode = 0;
++
++#ifdef DEBUG
++ dev_err(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status);
++#endif
++
++ if (unlikely(status)) {
++ caam_qi2_strstatus(ctx->dev, status);
++ ecode = -EIO;
++ }
++
++ ahash_unmap_ctx(ctx->dev, edesc, req, digestsize, DMA_TO_DEVICE);
++ qi_cache_free(edesc);
++
++#ifdef DEBUG
++ print_hex_dump(KERN_ERR, "ctx@" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx,
++ ctx->ctx_len, 1);
++ if (req->result)
++ print_hex_dump(KERN_ERR, "result@" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, req->result,
++ digestsize, 1);
++#endif
++
++ req->base.complete(&req->base, ecode);
++}
++
++static void ahash_done_ctx_dst(void *cbk_ctx, u32 status)
++{
++ struct crypto_async_request *areq = cbk_ctx;
++ struct ahash_request *req = ahash_request_cast(areq);
++ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
++ struct caam_hash_state *state = ahash_request_ctx(req);
++ struct ahash_edesc *edesc = state->caam_req.edesc;
++ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
++ int ecode = 0;
++#ifdef DEBUG
++ int digestsize = crypto_ahash_digestsize(ahash);
++
++ dev_err(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status);
++#endif
++
++ if (unlikely(status)) {
++ caam_qi2_strstatus(ctx->dev, status);
++ ecode = -EIO;
++ }
++
++ ahash_unmap_ctx(ctx->dev, edesc, req, ctx->ctx_len, DMA_FROM_DEVICE);
++ switch_buf(state);
++ qi_cache_free(edesc);
++
++#ifdef DEBUG
++ print_hex_dump(KERN_ERR, "ctx@" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx,
++ ctx->ctx_len, 1);
++ if (req->result)
++ print_hex_dump(KERN_ERR, "result@" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, req->result,
++ digestsize, 1);
++#endif
++
++ req->base.complete(&req->base, ecode);
++}
++
++static int ahash_update_ctx(struct ahash_request *req)
++{
++ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
++ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
++ struct caam_hash_state *state = ahash_request_ctx(req);
++ struct caam_request *req_ctx = &state->caam_req;
++ struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1];
++ struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
++ GFP_KERNEL : GFP_ATOMIC;
++ u8 *buf = current_buf(state);
++ int *buflen = current_buflen(state);
++ u8 *next_buf = alt_buf(state);
++ int *next_buflen = alt_buflen(state), last_buflen;
++ int in_len = *buflen + req->nbytes, to_hash;
++ int src_nents, mapped_nents, qm_sg_bytes, qm_sg_src_index;
++ struct ahash_edesc *edesc;
++ int ret = 0;
++
++ last_buflen = *next_buflen;
++ *next_buflen = in_len & (crypto_tfm_alg_blocksize(&ahash->base) - 1);
++ to_hash = in_len - *next_buflen;
++
++ if (to_hash) {
++ struct dpaa2_sg_entry *sg_table;
++
++ src_nents = sg_nents_for_len(req->src,
++ req->nbytes - (*next_buflen));
++ if (src_nents < 0) {
++ dev_err(ctx->dev, "Invalid number of src SG.\n");
++ return src_nents;
++ }
++
++ if (src_nents) {
++ mapped_nents = dma_map_sg(ctx->dev, req->src, src_nents,
++ DMA_TO_DEVICE);
++ if (!mapped_nents) {
++ dev_err(ctx->dev, "unable to DMA map source\n");
++ return -ENOMEM;
++ }
++ } else {
++ mapped_nents = 0;
++ }
++
++ /* allocate space for base edesc and link tables */
++ edesc = qi_cache_zalloc(GFP_DMA | flags);
++ if (!edesc) {
++ dma_unmap_sg(ctx->dev, req->src, src_nents,
++ DMA_TO_DEVICE);
++ return -ENOMEM;
++ }
++
++ edesc->src_nents = src_nents;
++ qm_sg_src_index = 1 + (*buflen ? 1 : 0);
++ qm_sg_bytes = (qm_sg_src_index + mapped_nents) *
++ sizeof(*sg_table);
++ sg_table = &edesc->sgt[0];
++
++ ret = ctx_map_to_qm_sg(ctx->dev, state, ctx->ctx_len, sg_table,
++ DMA_BIDIRECTIONAL);
++ if (ret)
++ goto unmap_ctx;
++
++ ret = buf_map_to_qm_sg(ctx->dev, sg_table + 1, state);
++ if (ret)
++ goto unmap_ctx;
++
++ if (mapped_nents) {
++ sg_to_qm_sg_last(req->src, mapped_nents,
++ sg_table + qm_sg_src_index, 0);
++ if (*next_buflen)
++ scatterwalk_map_and_copy(next_buf, req->src,
++ to_hash - *buflen,
++ *next_buflen, 0);
++ } else {
++ dpaa2_sg_set_final(sg_table + qm_sg_src_index - 1,
++ true);
++ }
++
++ edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table,
++ qm_sg_bytes, DMA_TO_DEVICE);
++ if (dma_mapping_error(ctx->dev, edesc->qm_sg_dma)) {
++ dev_err(ctx->dev, "unable to map S/G table\n");
++ ret = -ENOMEM;
++ goto unmap_ctx;
++ }
++ edesc->qm_sg_bytes = qm_sg_bytes;
++
++ memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt));
++ dpaa2_fl_set_final(in_fle, true);
++ dpaa2_fl_set_format(in_fle, dpaa2_fl_sg);
++ dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma);
++ dpaa2_fl_set_len(in_fle, ctx->ctx_len + to_hash);
++ dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
++ dpaa2_fl_set_addr(out_fle, state->ctx_dma);
++ dpaa2_fl_set_len(out_fle, ctx->ctx_len);
++
++ req_ctx->flc = &ctx->flc[UPDATE];
++ req_ctx->flc_dma = ctx->flc_dma[UPDATE];
++ req_ctx->cbk = ahash_done_bi;
++ req_ctx->ctx = &req->base;
++ req_ctx->edesc = edesc;
++
++ ret = dpaa2_caam_enqueue(ctx->dev, req_ctx);
++ if (ret != -EINPROGRESS &&
++ !(ret == -EBUSY &&
++ req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
++ goto unmap_ctx;
++ } else if (*next_buflen) {
++ scatterwalk_map_and_copy(buf + *buflen, req->src, 0,
++ req->nbytes, 0);
++ *buflen = *next_buflen;
++ *next_buflen = last_buflen;
++ }
++#ifdef DEBUG
++ print_hex_dump(KERN_ERR, "buf@" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, buf, *buflen, 1);
++ print_hex_dump(KERN_ERR, "next buf@" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, next_buf,
++ *next_buflen, 1);
++#endif
++
++ return ret;
++unmap_ctx:
++ ahash_unmap_ctx(ctx->dev, edesc, req, ctx->ctx_len, DMA_BIDIRECTIONAL);
++ qi_cache_free(edesc);
++ return ret;
++}
++
++static int ahash_final_ctx(struct ahash_request *req)
++{
++ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
++ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
++ struct caam_hash_state *state = ahash_request_ctx(req);
++ struct caam_request *req_ctx = &state->caam_req;
++ struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1];
++ struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
++ GFP_KERNEL : GFP_ATOMIC;
++ int buflen = *current_buflen(state);
++ int qm_sg_bytes, qm_sg_src_index;
++ int digestsize = crypto_ahash_digestsize(ahash);
++ struct ahash_edesc *edesc;
++ struct dpaa2_sg_entry *sg_table;
++ int ret;
++
++ /* allocate space for base edesc and link tables */
++ edesc = qi_cache_zalloc(GFP_DMA | flags);
++ if (!edesc)
++ return -ENOMEM;
++
++ qm_sg_src_index = 1 + (buflen ? 1 : 0);
++ qm_sg_bytes = qm_sg_src_index * sizeof(*sg_table);
++ sg_table = &edesc->sgt[0];
++
++ ret = ctx_map_to_qm_sg(ctx->dev, state, ctx->ctx_len, sg_table,
++ DMA_TO_DEVICE);
++ if (ret)
++ goto unmap_ctx;
++
++ ret = buf_map_to_qm_sg(ctx->dev, sg_table + 1, state);
++ if (ret)
++ goto unmap_ctx;
++
++ dpaa2_sg_set_final(sg_table + qm_sg_src_index - 1, true);
++
++ edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table, qm_sg_bytes,
++ DMA_TO_DEVICE);
++ if (dma_mapping_error(ctx->dev, edesc->qm_sg_dma)) {
++ dev_err(ctx->dev, "unable to map S/G table\n");
++ ret = -ENOMEM;
++ goto unmap_ctx;
++ }
++ edesc->qm_sg_bytes = qm_sg_bytes;
++
++ edesc->dst_dma = dma_map_single(ctx->dev, req->result, digestsize,
++ DMA_FROM_DEVICE);
++ if (dma_mapping_error(ctx->dev, edesc->dst_dma)) {
++ dev_err(ctx->dev, "unable to map dst\n");
++ edesc->dst_dma = 0;
++ ret = -ENOMEM;
++ goto unmap_ctx;
++ }
++
++ memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt));
++ dpaa2_fl_set_final(in_fle, true);
++ dpaa2_fl_set_format(in_fle, dpaa2_fl_sg);
++ dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma);
++ dpaa2_fl_set_len(in_fle, ctx->ctx_len + buflen);
++ dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
++ dpaa2_fl_set_addr(out_fle, edesc->dst_dma);
++ dpaa2_fl_set_len(out_fle, digestsize);
++
++ req_ctx->flc = &ctx->flc[FINALIZE];
++ req_ctx->flc_dma = ctx->flc_dma[FINALIZE];
++ req_ctx->cbk = ahash_done_ctx_src;
++ req_ctx->ctx = &req->base;
++ req_ctx->edesc = edesc;
++
++ ret = dpaa2_caam_enqueue(ctx->dev, req_ctx);
++ if (ret == -EINPROGRESS ||
++ (ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
++ return ret;
++
++unmap_ctx:
++ ahash_unmap_ctx(ctx->dev, edesc, req, digestsize, DMA_FROM_DEVICE);
++ qi_cache_free(edesc);
++ return ret;
++}
++
++static int ahash_finup_ctx(struct ahash_request *req)
++{
++ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
++ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
++ struct caam_hash_state *state = ahash_request_ctx(req);
++ struct caam_request *req_ctx = &state->caam_req;
++ struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1];
++ struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
++ GFP_KERNEL : GFP_ATOMIC;
++ int buflen = *current_buflen(state);
++ int qm_sg_bytes, qm_sg_src_index;
++ int src_nents, mapped_nents;
++ int digestsize = crypto_ahash_digestsize(ahash);
++ struct ahash_edesc *edesc;
++ struct dpaa2_sg_entry *sg_table;
++ int ret;
++
++ src_nents = sg_nents_for_len(req->src, req->nbytes);
++ if (src_nents < 0) {
++ dev_err(ctx->dev, "Invalid number of src SG.\n");
++ return src_nents;
++ }
++
++ if (src_nents) {
++ mapped_nents = dma_map_sg(ctx->dev, req->src, src_nents,
++ DMA_TO_DEVICE);
++ if (!mapped_nents) {
++ dev_err(ctx->dev, "unable to DMA map source\n");
++ return -ENOMEM;
++ }
++ } else {
++ mapped_nents = 0;
++ }
++
++ /* allocate space for base edesc and link tables */
++ edesc = qi_cache_zalloc(GFP_DMA | flags);
++ if (!edesc) {
++ dma_unmap_sg(ctx->dev, req->src, src_nents, DMA_TO_DEVICE);
++ return -ENOMEM;
++ }
++
++ edesc->src_nents = src_nents;
++ qm_sg_src_index = 1 + (buflen ? 1 : 0);
++ qm_sg_bytes = (qm_sg_src_index + mapped_nents) * sizeof(*sg_table);
++ sg_table = &edesc->sgt[0];
++
++ ret = ctx_map_to_qm_sg(ctx->dev, state, ctx->ctx_len, sg_table,
++ DMA_TO_DEVICE);
++ if (ret)
++ goto unmap_ctx;
++
++ ret = buf_map_to_qm_sg(ctx->dev, sg_table + 1, state);
++ if (ret)
++ goto unmap_ctx;
++
++ sg_to_qm_sg_last(req->src, mapped_nents, sg_table + qm_sg_src_index, 0);
++
++ edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table, qm_sg_bytes,
++ DMA_TO_DEVICE);
++ if (dma_mapping_error(ctx->dev, edesc->qm_sg_dma)) {
++ dev_err(ctx->dev, "unable to map S/G table\n");
++ ret = -ENOMEM;
++ goto unmap_ctx;
++ }
++ edesc->qm_sg_bytes = qm_sg_bytes;
++
++ edesc->dst_dma = dma_map_single(ctx->dev, req->result, digestsize,
++ DMA_FROM_DEVICE);
++ if (dma_mapping_error(ctx->dev, edesc->dst_dma)) {
++ dev_err(ctx->dev, "unable to map dst\n");
++ edesc->dst_dma = 0;
++ ret = -ENOMEM;
++ goto unmap_ctx;
++ }
++
++ memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt));
++ dpaa2_fl_set_final(in_fle, true);
++ dpaa2_fl_set_format(in_fle, dpaa2_fl_sg);
++ dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma);
++ dpaa2_fl_set_len(in_fle, ctx->ctx_len + buflen + req->nbytes);
++ dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
++ dpaa2_fl_set_addr(out_fle, edesc->dst_dma);
++ dpaa2_fl_set_len(out_fle, digestsize);
++
++ req_ctx->flc = &ctx->flc[FINALIZE];
++ req_ctx->flc_dma = ctx->flc_dma[FINALIZE];
++ req_ctx->cbk = ahash_done_ctx_src;
++ req_ctx->ctx = &req->base;
++ req_ctx->edesc = edesc;
++
++ ret = dpaa2_caam_enqueue(ctx->dev, req_ctx);
++ if (ret == -EINPROGRESS ||
++ (ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
++ return ret;
++
++unmap_ctx:
++ ahash_unmap_ctx(ctx->dev, edesc, req, digestsize, DMA_FROM_DEVICE);
++ qi_cache_free(edesc);
++ return ret;
++}
++
++static int ahash_digest(struct ahash_request *req)
++{
++ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
++ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
++ struct caam_hash_state *state = ahash_request_ctx(req);
++ struct caam_request *req_ctx = &state->caam_req;
++ struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1];
++ struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
++ GFP_KERNEL : GFP_ATOMIC;
++ int digestsize = crypto_ahash_digestsize(ahash);
++ int src_nents, mapped_nents;
++ struct ahash_edesc *edesc;
++ int ret = -ENOMEM;
++
++ state->buf_dma = 0;
++
++ src_nents = sg_nents_for_len(req->src, req->nbytes);
++ if (src_nents < 0) {
++ dev_err(ctx->dev, "Invalid number of src SG.\n");
++ return src_nents;
++ }
++
++ if (src_nents) {
++ mapped_nents = dma_map_sg(ctx->dev, req->src, src_nents,
++ DMA_TO_DEVICE);
++ if (!mapped_nents) {
++ dev_err(ctx->dev, "unable to map source for DMA\n");
++ return ret;
++ }
++ } else {
++ mapped_nents = 0;
++ }
++
++ /* allocate space for base edesc and link tables */
++ edesc = qi_cache_zalloc(GFP_DMA | flags);
++ if (!edesc) {
++ dma_unmap_sg(ctx->dev, req->src, src_nents, DMA_TO_DEVICE);
++ return ret;
++ }
++
++ edesc->src_nents = src_nents;
++ memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt));
++
++ if (mapped_nents > 1) {
++ int qm_sg_bytes;
++ struct dpaa2_sg_entry *sg_table = &edesc->sgt[0];
++
++ qm_sg_bytes = mapped_nents * sizeof(*sg_table);
++ sg_to_qm_sg_last(req->src, mapped_nents, sg_table, 0);
++ edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table,
++ qm_sg_bytes, DMA_TO_DEVICE);
++ if (dma_mapping_error(ctx->dev, edesc->qm_sg_dma)) {
++ dev_err(ctx->dev, "unable to map S/G table\n");
++ goto unmap;
++ }
++ edesc->qm_sg_bytes = qm_sg_bytes;
++ dpaa2_fl_set_format(in_fle, dpaa2_fl_sg);
++ dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma);
++ } else {
++ dpaa2_fl_set_format(in_fle, dpaa2_fl_single);
++ dpaa2_fl_set_addr(in_fle, sg_dma_address(req->src));
++ }
++
++ edesc->dst_dma = dma_map_single(ctx->dev, req->result, digestsize,
++ DMA_FROM_DEVICE);
++ if (dma_mapping_error(ctx->dev, edesc->dst_dma)) {
++ dev_err(ctx->dev, "unable to map dst\n");
++ edesc->dst_dma = 0;
++ goto unmap;
++ }
++
++ dpaa2_fl_set_final(in_fle, true);
++ dpaa2_fl_set_len(in_fle, req->nbytes);
++ dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
++ dpaa2_fl_set_addr(out_fle, edesc->dst_dma);
++ dpaa2_fl_set_len(out_fle, digestsize);
++
++ req_ctx->flc = &ctx->flc[DIGEST];
++ req_ctx->flc_dma = ctx->flc_dma[DIGEST];
++ req_ctx->cbk = ahash_done;
++ req_ctx->ctx = &req->base;
++ req_ctx->edesc = edesc;
++ ret = dpaa2_caam_enqueue(ctx->dev, req_ctx);
++ if (ret == -EINPROGRESS ||
++ (ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
++ return ret;
++
++unmap:
++ ahash_unmap(ctx->dev, edesc, req, digestsize);
++ qi_cache_free(edesc);
++ return ret;
++}
++
++static int ahash_final_no_ctx(struct ahash_request *req)
++{
++ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
++ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
++ struct caam_hash_state *state = ahash_request_ctx(req);
++ struct caam_request *req_ctx = &state->caam_req;
++ struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1];
++ struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
++ GFP_KERNEL : GFP_ATOMIC;
++ u8 *buf = current_buf(state);
++ int buflen = *current_buflen(state);
++ int digestsize = crypto_ahash_digestsize(ahash);
++ struct ahash_edesc *edesc;
++ int ret = -ENOMEM;
++
++ /* allocate space for base edesc and link tables */
++ edesc = qi_cache_zalloc(GFP_DMA | flags);
++ if (!edesc)
++ return ret;
++
++ state->buf_dma = dma_map_single(ctx->dev, buf, buflen, DMA_TO_DEVICE);
++ if (dma_mapping_error(ctx->dev, state->buf_dma)) {
++ dev_err(ctx->dev, "unable to map src\n");
++ goto unmap;
++ }
++
++ edesc->dst_dma = dma_map_single(ctx->dev, req->result, digestsize,
++ DMA_FROM_DEVICE);
++ if (dma_mapping_error(ctx->dev, edesc->dst_dma)) {
++ dev_err(ctx->dev, "unable to map dst\n");
++ edesc->dst_dma = 0;
++ goto unmap;
++ }
++
++ memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt));
++ dpaa2_fl_set_final(in_fle, true);
++ dpaa2_fl_set_format(in_fle, dpaa2_fl_single);
++ dpaa2_fl_set_addr(in_fle, state->buf_dma);
++ dpaa2_fl_set_len(in_fle, buflen);
++ dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
++ dpaa2_fl_set_addr(out_fle, edesc->dst_dma);
++ dpaa2_fl_set_len(out_fle, digestsize);
++
++ req_ctx->flc = &ctx->flc[DIGEST];
++ req_ctx->flc_dma = ctx->flc_dma[DIGEST];
++ req_ctx->cbk = ahash_done;
++ req_ctx->ctx = &req->base;
++ req_ctx->edesc = edesc;
++
++ ret = dpaa2_caam_enqueue(ctx->dev, req_ctx);
++ if (ret == -EINPROGRESS ||
++ (ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
++ return ret;
++
++unmap:
++ ahash_unmap(ctx->dev, edesc, req, digestsize);
++ qi_cache_free(edesc);
++ return ret;
++}
++
++static int ahash_update_no_ctx(struct ahash_request *req)
++{
++ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
++ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
++ struct caam_hash_state *state = ahash_request_ctx(req);
++ struct caam_request *req_ctx = &state->caam_req;
++ struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1];
++ struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
++ GFP_KERNEL : GFP_ATOMIC;
++ u8 *buf = current_buf(state);
++ int *buflen = current_buflen(state);
++ u8 *next_buf = alt_buf(state);
++ int *next_buflen = alt_buflen(state);
++ int in_len = *buflen + req->nbytes, to_hash;
++ int qm_sg_bytes, src_nents, mapped_nents;
++ struct ahash_edesc *edesc;
++ int ret = 0;
++
++ *next_buflen = in_len & (crypto_tfm_alg_blocksize(&ahash->base) - 1);
++ to_hash = in_len - *next_buflen;
++
++ if (to_hash) {
++ struct dpaa2_sg_entry *sg_table;
++
++ src_nents = sg_nents_for_len(req->src,
++ req->nbytes - *next_buflen);
++ if (src_nents < 0) {
++ dev_err(ctx->dev, "Invalid number of src SG.\n");
++ return src_nents;
++ }
++
++ if (src_nents) {
++ mapped_nents = dma_map_sg(ctx->dev, req->src, src_nents,
++ DMA_TO_DEVICE);
++ if (!mapped_nents) {
++ dev_err(ctx->dev, "unable to DMA map source\n");
++ return -ENOMEM;
++ }
++ } else {
++ mapped_nents = 0;
++ }
++
++ /* allocate space for base edesc and link tables */
++ edesc = qi_cache_zalloc(GFP_DMA | flags);
++ if (!edesc) {
++ dma_unmap_sg(ctx->dev, req->src, src_nents,
++ DMA_TO_DEVICE);
++ return -ENOMEM;
++ }
++
++ edesc->src_nents = src_nents;
++ qm_sg_bytes = (1 + mapped_nents) * sizeof(*sg_table);
++ sg_table = &edesc->sgt[0];
++
++ ret = buf_map_to_qm_sg(ctx->dev, sg_table, state);
++ if (ret)
++ goto unmap_ctx;
++
++ sg_to_qm_sg_last(req->src, mapped_nents, sg_table + 1, 0);
++
++ if (*next_buflen)
++ scatterwalk_map_and_copy(next_buf, req->src,
++ to_hash - *buflen,
++ *next_buflen, 0);
++
++ edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table,
++ qm_sg_bytes, DMA_TO_DEVICE);
++ if (dma_mapping_error(ctx->dev, edesc->qm_sg_dma)) {
++ dev_err(ctx->dev, "unable to map S/G table\n");
++ ret = -ENOMEM;
++ goto unmap_ctx;
++ }
++ edesc->qm_sg_bytes = qm_sg_bytes;
++
++ state->ctx_dma = dma_map_single(ctx->dev, state->caam_ctx,
++ ctx->ctx_len, DMA_FROM_DEVICE);
++ if (dma_mapping_error(ctx->dev, state->ctx_dma)) {
++ dev_err(ctx->dev, "unable to map ctx\n");
++ state->ctx_dma = 0;
++ ret = -ENOMEM;
++ goto unmap_ctx;
++ }
++
++ memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt));
++ dpaa2_fl_set_final(in_fle, true);
++ dpaa2_fl_set_format(in_fle, dpaa2_fl_sg);
++ dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma);
++ dpaa2_fl_set_len(in_fle, to_hash);
++ dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
++ dpaa2_fl_set_addr(out_fle, state->ctx_dma);
++ dpaa2_fl_set_len(out_fle, ctx->ctx_len);
++
++ req_ctx->flc = &ctx->flc[UPDATE_FIRST];
++ req_ctx->flc_dma = ctx->flc_dma[UPDATE_FIRST];
++ req_ctx->cbk = ahash_done_ctx_dst;
++ req_ctx->ctx = &req->base;
++ req_ctx->edesc = edesc;
++
++ ret = dpaa2_caam_enqueue(ctx->dev, req_ctx);
++ if (ret != -EINPROGRESS &&
++ !(ret == -EBUSY &&
++ req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
++ goto unmap_ctx;
++
++ state->update = ahash_update_ctx;
++ state->finup = ahash_finup_ctx;
++ state->final = ahash_final_ctx;
++ } else if (*next_buflen) {
++ scatterwalk_map_and_copy(buf + *buflen, req->src, 0,
++ req->nbytes, 0);
++ *buflen = *next_buflen;
++ *next_buflen = 0;
++ }
++#ifdef DEBUG
++ print_hex_dump(KERN_ERR, "buf@" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, buf, *buflen, 1);
++ print_hex_dump(KERN_ERR, "next buf@" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, next_buf,
++ *next_buflen, 1);
++#endif
++
++ return ret;
++unmap_ctx:
++ ahash_unmap_ctx(ctx->dev, edesc, req, ctx->ctx_len, DMA_TO_DEVICE);
++ qi_cache_free(edesc);
++ return ret;
++}
++
++static int ahash_finup_no_ctx(struct ahash_request *req)
++{
++ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
++ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
++ struct caam_hash_state *state = ahash_request_ctx(req);
++ struct caam_request *req_ctx = &state->caam_req;
++ struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1];
++ struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
++ GFP_KERNEL : GFP_ATOMIC;
++ int buflen = *current_buflen(state);
++ int qm_sg_bytes, src_nents, mapped_nents;
++ int digestsize = crypto_ahash_digestsize(ahash);
++ struct ahash_edesc *edesc;
++ struct dpaa2_sg_entry *sg_table;
++ int ret;
++
++ src_nents = sg_nents_for_len(req->src, req->nbytes);
++ if (src_nents < 0) {
++ dev_err(ctx->dev, "Invalid number of src SG.\n");
++ return src_nents;
++ }
++
++ if (src_nents) {
++ mapped_nents = dma_map_sg(ctx->dev, req->src, src_nents,
++ DMA_TO_DEVICE);
++ if (!mapped_nents) {
++ dev_err(ctx->dev, "unable to DMA map source\n");
++ return -ENOMEM;
++ }
++ } else {
++ mapped_nents = 0;
++ }
++
++ /* allocate space for base edesc and link tables */
++ edesc = qi_cache_zalloc(GFP_DMA | flags);
++ if (!edesc) {
++ dma_unmap_sg(ctx->dev, req->src, src_nents, DMA_TO_DEVICE);
++ return -ENOMEM;
++ }
++
++ edesc->src_nents = src_nents;
++ qm_sg_bytes = (2 + mapped_nents) * sizeof(*sg_table);
++ sg_table = &edesc->sgt[0];
++
++ ret = buf_map_to_qm_sg(ctx->dev, sg_table, state);
++ if (ret)
++ goto unmap;
++
++ sg_to_qm_sg_last(req->src, mapped_nents, sg_table + 1, 0);
++
++ edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table, qm_sg_bytes,
++ DMA_TO_DEVICE);
++ if (dma_mapping_error(ctx->dev, edesc->qm_sg_dma)) {
++ dev_err(ctx->dev, "unable to map S/G table\n");
++ ret = -ENOMEM;
++ goto unmap;
++ }
++ edesc->qm_sg_bytes = qm_sg_bytes;
++
++ edesc->dst_dma = dma_map_single(ctx->dev, req->result, digestsize,
++ DMA_FROM_DEVICE);
++ if (dma_mapping_error(ctx->dev, edesc->dst_dma)) {
++ dev_err(ctx->dev, "unable to map dst\n");
++ edesc->dst_dma = 0;
++ ret = -ENOMEM;
++ goto unmap;
++ }
++
++ memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt));
++ dpaa2_fl_set_final(in_fle, true);
++ dpaa2_fl_set_format(in_fle, dpaa2_fl_sg);
++ dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma);
++ dpaa2_fl_set_len(in_fle, buflen + req->nbytes);
++ dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
++ dpaa2_fl_set_addr(out_fle, edesc->dst_dma);
++ dpaa2_fl_set_len(out_fle, digestsize);
++
++ req_ctx->flc = &ctx->flc[DIGEST];
++ req_ctx->flc_dma = ctx->flc_dma[DIGEST];
++ req_ctx->cbk = ahash_done;
++ req_ctx->ctx = &req->base;
++ req_ctx->edesc = edesc;
++ ret = dpaa2_caam_enqueue(ctx->dev, req_ctx);
++ if (ret != -EINPROGRESS &&
++ !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
++ goto unmap;
++
++ return ret;
++unmap:
++ ahash_unmap(ctx->dev, edesc, req, digestsize);
++ qi_cache_free(edesc);
++ return -ENOMEM;
++}
++
++static int ahash_update_first(struct ahash_request *req)
++{
++ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
++ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
++ struct caam_hash_state *state = ahash_request_ctx(req);
++ struct caam_request *req_ctx = &state->caam_req;
++ struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1];
++ struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
++ GFP_KERNEL : GFP_ATOMIC;
++ u8 *next_buf = alt_buf(state);
++ int *next_buflen = alt_buflen(state);
++ int to_hash;
++ int src_nents, mapped_nents;
++ struct ahash_edesc *edesc;
++ int ret = 0;
++
++ *next_buflen = req->nbytes & (crypto_tfm_alg_blocksize(&ahash->base) -
++ 1);
++ to_hash = req->nbytes - *next_buflen;
++
++ if (to_hash) {
++ struct dpaa2_sg_entry *sg_table;
++
++ src_nents = sg_nents_for_len(req->src,
++ req->nbytes - (*next_buflen));
++ if (src_nents < 0) {
++ dev_err(ctx->dev, "Invalid number of src SG.\n");
++ return src_nents;
++ }
++
++ if (src_nents) {
++ mapped_nents = dma_map_sg(ctx->dev, req->src, src_nents,
++ DMA_TO_DEVICE);
++ if (!mapped_nents) {
++ dev_err(ctx->dev, "unable to map source for DMA\n");
++ return -ENOMEM;
++ }
++ } else {
++ mapped_nents = 0;
++ }
++
++ /* allocate space for base edesc and link tables */
++ edesc = qi_cache_zalloc(GFP_DMA | flags);
++ if (!edesc) {
++ dma_unmap_sg(ctx->dev, req->src, src_nents,
++ DMA_TO_DEVICE);
++ return -ENOMEM;
++ }
++
++ edesc->src_nents = src_nents;
++ sg_table = &edesc->sgt[0];
++
++ memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt));
++ dpaa2_fl_set_final(in_fle, true);
++ dpaa2_fl_set_len(in_fle, to_hash);
++
++ if (mapped_nents > 1) {
++ int qm_sg_bytes;
++
++ sg_to_qm_sg_last(req->src, mapped_nents, sg_table, 0);
++ qm_sg_bytes = mapped_nents * sizeof(*sg_table);
++ edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table,
++ qm_sg_bytes,
++ DMA_TO_DEVICE);
++ if (dma_mapping_error(ctx->dev, edesc->qm_sg_dma)) {
++ dev_err(ctx->dev, "unable to map S/G table\n");
++ ret = -ENOMEM;
++ goto unmap_ctx;
++ }
++ edesc->qm_sg_bytes = qm_sg_bytes;
++ dpaa2_fl_set_format(in_fle, dpaa2_fl_sg);
++ dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma);
++ } else {
++ dpaa2_fl_set_format(in_fle, dpaa2_fl_single);
++ dpaa2_fl_set_addr(in_fle, sg_dma_address(req->src));
++ }
++
++ if (*next_buflen)
++ scatterwalk_map_and_copy(next_buf, req->src, to_hash,
++ *next_buflen, 0);
++
++ state->ctx_dma = dma_map_single(ctx->dev, state->caam_ctx,
++ ctx->ctx_len, DMA_FROM_DEVICE);
++ if (dma_mapping_error(ctx->dev, state->ctx_dma)) {
++ dev_err(ctx->dev, "unable to map ctx\n");
++ state->ctx_dma = 0;
++ ret = -ENOMEM;
++ goto unmap_ctx;
++ }
++
++ dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
++ dpaa2_fl_set_addr(out_fle, state->ctx_dma);
++ dpaa2_fl_set_len(out_fle, ctx->ctx_len);
++
++ req_ctx->flc = &ctx->flc[UPDATE_FIRST];
++ req_ctx->flc_dma = ctx->flc_dma[UPDATE_FIRST];
++ req_ctx->cbk = ahash_done_ctx_dst;
++ req_ctx->ctx = &req->base;
++ req_ctx->edesc = edesc;
++
++ ret = dpaa2_caam_enqueue(ctx->dev, req_ctx);
++ if (ret != -EINPROGRESS &&
++ !(ret == -EBUSY && req->base.flags &
++ CRYPTO_TFM_REQ_MAY_BACKLOG))
++ goto unmap_ctx;
++
++ state->update = ahash_update_ctx;
++ state->finup = ahash_finup_ctx;
++ state->final = ahash_final_ctx;
++ } else if (*next_buflen) {
++ state->update = ahash_update_no_ctx;
++ state->finup = ahash_finup_no_ctx;
++ state->final = ahash_final_no_ctx;
++ scatterwalk_map_and_copy(next_buf, req->src, 0,
++ req->nbytes, 0);
++ switch_buf(state);
++ }
++#ifdef DEBUG
++ print_hex_dump(KERN_ERR, "next buf@" __stringify(__LINE__)": ",
++ DUMP_PREFIX_ADDRESS, 16, 4, next_buf, *next_buflen, 1);
++#endif
++
++ return ret;
++unmap_ctx:
++ ahash_unmap_ctx(ctx->dev, edesc, req, ctx->ctx_len, DMA_TO_DEVICE);
++ qi_cache_free(edesc);
++ return ret;
++}
++
++static int ahash_finup_first(struct ahash_request *req)
++{
++ return ahash_digest(req);
++}
++
++static int ahash_init(struct ahash_request *req)
++{
++ struct caam_hash_state *state = ahash_request_ctx(req);
++
++ state->update = ahash_update_first;
++ state->finup = ahash_finup_first;
++ state->final = ahash_final_no_ctx;
++
++ state->ctx_dma = 0;
++ state->current_buf = 0;
++ state->buf_dma = 0;
++ state->buflen_0 = 0;
++ state->buflen_1 = 0;
++
++ return 0;
++}
++
++static int ahash_update(struct ahash_request *req)
++{
++ struct caam_hash_state *state = ahash_request_ctx(req);
++
++ return state->update(req);
++}
++
++static int ahash_finup(struct ahash_request *req)
++{
++ struct caam_hash_state *state = ahash_request_ctx(req);
++
++ return state->finup(req);
++}
++
++static int ahash_final(struct ahash_request *req)
++{
++ struct caam_hash_state *state = ahash_request_ctx(req);
++
++ return state->final(req);
++}
++
++static int ahash_export(struct ahash_request *req, void *out)
++{
++ struct caam_hash_state *state = ahash_request_ctx(req);
++ struct caam_export_state *export = out;
++ int len;
++ u8 *buf;
++
++ if (state->current_buf) {
++ buf = state->buf_1;
++ len = state->buflen_1;
++ } else {
++ buf = state->buf_0;
++ len = state->buflen_0;
++ }
++
++ memcpy(export->buf, buf, len);
++ memcpy(export->caam_ctx, state->caam_ctx, sizeof(export->caam_ctx));
++ export->buflen = len;
++ export->update = state->update;
++ export->final = state->final;
++ export->finup = state->finup;
++
++ return 0;
++}
++
++static int ahash_import(struct ahash_request *req, const void *in)
++{
++ struct caam_hash_state *state = ahash_request_ctx(req);
++ const struct caam_export_state *export = in;
++
++ memset(state, 0, sizeof(*state));
++ memcpy(state->buf_0, export->buf, export->buflen);
++ memcpy(state->caam_ctx, export->caam_ctx, sizeof(state->caam_ctx));
++ state->buflen_0 = export->buflen;
++ state->update = export->update;
++ state->final = export->final;
++ state->finup = export->finup;
++
++ return 0;
++}
++
++struct caam_hash_template {
++ char name[CRYPTO_MAX_ALG_NAME];
++ char driver_name[CRYPTO_MAX_ALG_NAME];
++ char hmac_name[CRYPTO_MAX_ALG_NAME];
++ char hmac_driver_name[CRYPTO_MAX_ALG_NAME];
++ unsigned int blocksize;
++ struct ahash_alg template_ahash;
++ u32 alg_type;
++};
++
++/* ahash descriptors */
++static struct caam_hash_template driver_hash[] = {
++ {
++ .name = "sha1",
++ .driver_name = "sha1-caam-qi2",
++ .hmac_name = "hmac(sha1)",
++ .hmac_driver_name = "hmac-sha1-caam-qi2",
++ .blocksize = SHA1_BLOCK_SIZE,
++ .template_ahash = {
++ .init = ahash_init,
++ .update = ahash_update,
++ .final = ahash_final,
++ .finup = ahash_finup,
++ .digest = ahash_digest,
++ .export = ahash_export,
++ .import = ahash_import,
++ .setkey = ahash_setkey,
++ .halg = {
++ .digestsize = SHA1_DIGEST_SIZE,
++ .statesize = sizeof(struct caam_export_state),
++ },
++ },
++ .alg_type = OP_ALG_ALGSEL_SHA1,
++ }, {
++ .name = "sha224",
++ .driver_name = "sha224-caam-qi2",
++ .hmac_name = "hmac(sha224)",
++ .hmac_driver_name = "hmac-sha224-caam-qi2",
++ .blocksize = SHA224_BLOCK_SIZE,
++ .template_ahash = {
++ .init = ahash_init,
++ .update = ahash_update,
++ .final = ahash_final,
++ .finup = ahash_finup,
++ .digest = ahash_digest,
++ .export = ahash_export,
++ .import = ahash_import,
++ .setkey = ahash_setkey,
++ .halg = {
++ .digestsize = SHA224_DIGEST_SIZE,
++ .statesize = sizeof(struct caam_export_state),
++ },
++ },
++ .alg_type = OP_ALG_ALGSEL_SHA224,
++ }, {
++ .name = "sha256",
++ .driver_name = "sha256-caam-qi2",
++ .hmac_name = "hmac(sha256)",
++ .hmac_driver_name = "hmac-sha256-caam-qi2",
++ .blocksize = SHA256_BLOCK_SIZE,
++ .template_ahash = {
++ .init = ahash_init,
++ .update = ahash_update,
++ .final = ahash_final,
++ .finup = ahash_finup,
++ .digest = ahash_digest,
++ .export = ahash_export,
++ .import = ahash_import,
++ .setkey = ahash_setkey,
++ .halg = {
++ .digestsize = SHA256_DIGEST_SIZE,
++ .statesize = sizeof(struct caam_export_state),
++ },
++ },
++ .alg_type = OP_ALG_ALGSEL_SHA256,
++ }, {
++ .name = "sha384",
++ .driver_name = "sha384-caam-qi2",
++ .hmac_name = "hmac(sha384)",
++ .hmac_driver_name = "hmac-sha384-caam-qi2",
++ .blocksize = SHA384_BLOCK_SIZE,
++ .template_ahash = {
++ .init = ahash_init,
++ .update = ahash_update,
++ .final = ahash_final,
++ .finup = ahash_finup,
++ .digest = ahash_digest,
++ .export = ahash_export,
++ .import = ahash_import,
++ .setkey = ahash_setkey,
++ .halg = {
++ .digestsize = SHA384_DIGEST_SIZE,
++ .statesize = sizeof(struct caam_export_state),
++ },
++ },
++ .alg_type = OP_ALG_ALGSEL_SHA384,
++ }, {
++ .name = "sha512",
++ .driver_name = "sha512-caam-qi2",
++ .hmac_name = "hmac(sha512)",
++ .hmac_driver_name = "hmac-sha512-caam-qi2",
++ .blocksize = SHA512_BLOCK_SIZE,
++ .template_ahash = {
++ .init = ahash_init,
++ .update = ahash_update,
++ .final = ahash_final,
++ .finup = ahash_finup,
++ .digest = ahash_digest,
++ .export = ahash_export,
++ .import = ahash_import,
++ .setkey = ahash_setkey,
++ .halg = {
++ .digestsize = SHA512_DIGEST_SIZE,
++ .statesize = sizeof(struct caam_export_state),
++ },
++ },
++ .alg_type = OP_ALG_ALGSEL_SHA512,
++ }, {
++ .name = "md5",
++ .driver_name = "md5-caam-qi2",
++ .hmac_name = "hmac(md5)",
++ .hmac_driver_name = "hmac-md5-caam-qi2",
++ .blocksize = MD5_BLOCK_WORDS * 4,
++ .template_ahash = {
++ .init = ahash_init,
++ .update = ahash_update,
++ .final = ahash_final,
++ .finup = ahash_finup,
++ .digest = ahash_digest,
++ .export = ahash_export,
++ .import = ahash_import,
++ .setkey = ahash_setkey,
++ .halg = {
++ .digestsize = MD5_DIGEST_SIZE,
++ .statesize = sizeof(struct caam_export_state),
++ },
++ },
++ .alg_type = OP_ALG_ALGSEL_MD5,
++ }
++};
++
++struct caam_hash_alg {
++ struct list_head entry;
++ struct device *dev;
++ int alg_type;
++ struct ahash_alg ahash_alg;
++};
++
++static int caam_hash_cra_init(struct crypto_tfm *tfm)
++{
++ struct crypto_ahash *ahash = __crypto_ahash_cast(tfm);
++ struct crypto_alg *base = tfm->__crt_alg;
++ struct hash_alg_common *halg =
++ container_of(base, struct hash_alg_common, base);
++ struct ahash_alg *alg =
++ container_of(halg, struct ahash_alg, halg);
++ struct caam_hash_alg *caam_hash =
++ container_of(alg, struct caam_hash_alg, ahash_alg);
++ struct caam_hash_ctx *ctx = crypto_tfm_ctx(tfm);
++ /* Sizes for MDHA running digests: MD5, SHA1, 224, 256, 384, 512 */
++ static const u8 runninglen[] = { HASH_MSG_LEN + MD5_DIGEST_SIZE,
++ HASH_MSG_LEN + SHA1_DIGEST_SIZE,
++ HASH_MSG_LEN + 32,
++ HASH_MSG_LEN + SHA256_DIGEST_SIZE,
++ HASH_MSG_LEN + 64,
++ HASH_MSG_LEN + SHA512_DIGEST_SIZE };
++ dma_addr_t dma_addr;
++ int i;
++
++ ctx->dev = caam_hash->dev;
++
++ dma_addr = dma_map_single_attrs(ctx->dev, ctx->flc, sizeof(ctx->flc),
++ DMA_BIDIRECTIONAL,
++ DMA_ATTR_SKIP_CPU_SYNC);
++ if (dma_mapping_error(ctx->dev, dma_addr)) {
++ dev_err(ctx->dev, "unable to map shared descriptors\n");
++ return -ENOMEM;
++ }
++
++ for (i = 0; i < HASH_NUM_OP; i++)
++ ctx->flc_dma[i] = dma_addr + i * sizeof(ctx->flc[i]);
++
++ /* copy descriptor header template value */
++ ctx->adata.algtype = OP_TYPE_CLASS2_ALG | caam_hash->alg_type;
++
++ ctx->ctx_len = runninglen[(ctx->adata.algtype &
++ OP_ALG_ALGSEL_SUBMASK) >>
++ OP_ALG_ALGSEL_SHIFT];
++
++ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
++ sizeof(struct caam_hash_state));
++
++ return ahash_set_sh_desc(ahash);
++}
++
++static void caam_hash_cra_exit(struct crypto_tfm *tfm)
++{
++ struct caam_hash_ctx *ctx = crypto_tfm_ctx(tfm);
++
++ dma_unmap_single_attrs(ctx->dev, ctx->flc_dma[0], sizeof(ctx->flc),
++ DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC);
++}
++
++static struct caam_hash_alg *caam_hash_alloc(struct device *dev,
++ struct caam_hash_template *template, bool keyed)
++{
++ struct caam_hash_alg *t_alg;
++ struct ahash_alg *halg;
++ struct crypto_alg *alg;
++
++ t_alg = kzalloc(sizeof(*t_alg), GFP_KERNEL);
++ if (!t_alg)
++ return ERR_PTR(-ENOMEM);
++
++ t_alg->ahash_alg = template->template_ahash;
++ halg = &t_alg->ahash_alg;
++ alg = &halg->halg.base;
++
++ if (keyed) {
++ snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s",
++ template->hmac_name);
++ snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
++ template->hmac_driver_name);
++ } else {
++ snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s",
++ template->name);
++ snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
++ template->driver_name);
++ t_alg->ahash_alg.setkey = NULL;
++ }
++ alg->cra_module = THIS_MODULE;
++ alg->cra_init = caam_hash_cra_init;
++ alg->cra_exit = caam_hash_cra_exit;
++ alg->cra_ctxsize = sizeof(struct caam_hash_ctx);
++ alg->cra_priority = CAAM_CRA_PRIORITY;
++ alg->cra_blocksize = template->blocksize;
++ alg->cra_alignmask = 0;
++ alg->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_TYPE_AHASH;
++ alg->cra_type = &crypto_ahash_type;
++
++ t_alg->alg_type = template->alg_type;
++ t_alg->dev = dev;
++
++ return t_alg;
++}
++
++static void dpaa2_caam_fqdan_cb(struct dpaa2_io_notification_ctx *nctx)
++{
++ struct dpaa2_caam_priv_per_cpu *ppriv;
++
++ ppriv = container_of(nctx, struct dpaa2_caam_priv_per_cpu, nctx);
++ napi_schedule_irqoff(&ppriv->napi);
++}
++
++static int __cold dpaa2_dpseci_dpio_setup(struct dpaa2_caam_priv *priv)
++{
++ struct device *dev = priv->dev;
++ struct dpaa2_io_notification_ctx *nctx;
++ struct dpaa2_caam_priv_per_cpu *ppriv;
++ int err, i = 0, cpu;
++
++ for_each_online_cpu(cpu) {
++ ppriv = per_cpu_ptr(priv->ppriv, cpu);
++ ppriv->priv = priv;
++ nctx = &ppriv->nctx;
++ nctx->is_cdan = 0;
++ nctx->id = ppriv->rsp_fqid;
++ nctx->desired_cpu = cpu;
++ nctx->cb = dpaa2_caam_fqdan_cb;
++
++ /* Register notification callbacks */
++ err = dpaa2_io_service_register(NULL, nctx);
++ if (unlikely(err)) {
++ dev_dbg(dev, "No affine DPIO for cpu %d\n", cpu);
++ nctx->cb = NULL;
++ /*
++ * If no affine DPIO for this core, there's probably
++ * none available for next cores either. Signal we want
++ * to retry later, in case the DPIO devices weren't
++ * probed yet.
++ */
++ err = -EPROBE_DEFER;
++ goto err;
++ }
++
++ ppriv->store = dpaa2_io_store_create(DPAA2_CAAM_STORE_SIZE,
++ dev);
++ if (unlikely(!ppriv->store)) {
++ dev_err(dev, "dpaa2_io_store_create() failed\n");
++ goto err;
++ }
++
++ if (++i == priv->num_pairs)
++ break;
++ }
++
++ return 0;
++
++err:
++ for_each_online_cpu(cpu) {
++ ppriv = per_cpu_ptr(priv->ppriv, cpu);
++ if (!ppriv->nctx.cb)
++ break;
++ dpaa2_io_service_deregister(NULL, &ppriv->nctx);
++ }
++
++ for_each_online_cpu(cpu) {
++ ppriv = per_cpu_ptr(priv->ppriv, cpu);
++ if (!ppriv->store)
++ break;
++ dpaa2_io_store_destroy(ppriv->store);
++ }
++
++ return err;
++}
++
++static void __cold dpaa2_dpseci_dpio_free(struct dpaa2_caam_priv *priv)
++{
++ struct dpaa2_caam_priv_per_cpu *ppriv;
++ int i = 0, cpu;
++
++ for_each_online_cpu(cpu) {
++ ppriv = per_cpu_ptr(priv->ppriv, cpu);
++ dpaa2_io_service_deregister(NULL, &ppriv->nctx);
++ dpaa2_io_store_destroy(ppriv->store);
++
++ if (++i == priv->num_pairs)
++ return;
++ }
++}
++
++static int dpaa2_dpseci_bind(struct dpaa2_caam_priv *priv)
++{
++ struct dpseci_rx_queue_cfg rx_queue_cfg;
++ struct device *dev = priv->dev;
++ struct fsl_mc_device *ls_dev = to_fsl_mc_device(dev);
++ struct dpaa2_caam_priv_per_cpu *ppriv;
++ int err = 0, i = 0, cpu;
++
++ /* Configure Rx queues */
++ for_each_online_cpu(cpu) {
++ ppriv = per_cpu_ptr(priv->ppriv, cpu);
++
++ rx_queue_cfg.options = DPSECI_QUEUE_OPT_DEST |
++ DPSECI_QUEUE_OPT_USER_CTX;
++ rx_queue_cfg.order_preservation_en = 0;
++ rx_queue_cfg.dest_cfg.dest_type = DPSECI_DEST_DPIO;
++ rx_queue_cfg.dest_cfg.dest_id = ppriv->nctx.dpio_id;
++ /*
++ * Rx priority (WQ) doesn't really matter, since we use
++ * pull mode, i.e. volatile dequeues from specific FQs
++ */
++ rx_queue_cfg.dest_cfg.priority = 0;
++ rx_queue_cfg.user_ctx = ppriv->nctx.qman64;
++
++ err = dpseci_set_rx_queue(priv->mc_io, 0, ls_dev->mc_handle, i,
++ &rx_queue_cfg);
++ if (err) {
++ dev_err(dev, "dpseci_set_rx_queue() failed with err %d\n",
++ err);
++ return err;
++ }
++
++ if (++i == priv->num_pairs)
++ break;
++ }
++
++ return err;
++}
++
++static void dpaa2_dpseci_congestion_free(struct dpaa2_caam_priv *priv)
++{
++ struct device *dev = priv->dev;
++
++ if (!priv->cscn_mem)
++ return;
++
++ dma_unmap_single(dev, priv->cscn_dma, DPAA2_CSCN_SIZE, DMA_FROM_DEVICE);
++ kfree(priv->cscn_mem);
++}
++
++static void dpaa2_dpseci_free(struct dpaa2_caam_priv *priv)
++{
++ struct device *dev = priv->dev;
++ struct fsl_mc_device *ls_dev = to_fsl_mc_device(dev);
++
++ dpaa2_dpseci_congestion_free(priv);
++ dpseci_close(priv->mc_io, 0, ls_dev->mc_handle);
++}
++
++static void dpaa2_caam_process_fd(struct dpaa2_caam_priv *priv,
++ const struct dpaa2_fd *fd)
++{
++ struct caam_request *req;
++ u32 fd_err;
++
++ if (dpaa2_fd_get_format(fd) != dpaa2_fd_list) {
++ dev_err(priv->dev, "Only Frame List FD format is supported!\n");
++ return;
++ }
++
++ fd_err = dpaa2_fd_get_ctrl(fd) & FD_CTRL_ERR_MASK;
++ if (unlikely(fd_err))
++ dev_err(priv->dev, "FD error: %08x\n", fd_err);
++
++ /*
++ * FD[ADDR] is guaranteed to be valid, irrespective of errors reported
++ * in FD[ERR] or FD[FRC].
++ */
++ req = dpaa2_caam_iova_to_virt(priv, dpaa2_fd_get_addr(fd));
++ dma_unmap_single(priv->dev, req->fd_flt_dma, sizeof(req->fd_flt),
++ DMA_BIDIRECTIONAL);
++ req->cbk(req->ctx, dpaa2_fd_get_frc(fd));
++}
++
++static int dpaa2_caam_pull_fq(struct dpaa2_caam_priv_per_cpu *ppriv)
++{
++ int err;
++
++ /* Retry while portal is busy */
++ do {
++ err = dpaa2_io_service_pull_fq(NULL, ppriv->rsp_fqid,
++ ppriv->store);
++ } while (err == -EBUSY);
++
++ if (unlikely(err))
++ dev_err(ppriv->priv->dev, "dpaa2_io_service_pull err %d", err);
++
++ return err;
++}
++
++static int dpaa2_caam_store_consume(struct dpaa2_caam_priv_per_cpu *ppriv)
++{
++ struct dpaa2_dq *dq;
++ int cleaned = 0, is_last;
++
++ do {
++ dq = dpaa2_io_store_next(ppriv->store, &is_last);
++ if (unlikely(!dq)) {
++ if (unlikely(!is_last)) {
++ dev_dbg(ppriv->priv->dev,
++ "FQ %d returned no valid frames\n",
++ ppriv->rsp_fqid);
++ /*
++ * MUST retry until we get some sort of
++ * valid response token (be it "empty dequeue"
++ * or a valid frame).
++ */
++ continue;
++ }
++ break;
++ }
++
++ /* Process FD */
++ dpaa2_caam_process_fd(ppriv->priv, dpaa2_dq_fd(dq));
++ cleaned++;
++ } while (!is_last);
++
++ return cleaned;
++}
++
++static int dpaa2_dpseci_poll(struct napi_struct *napi, int budget)
++{
++ struct dpaa2_caam_priv_per_cpu *ppriv;
++ struct dpaa2_caam_priv *priv;
++ int err, cleaned = 0, store_cleaned;
++
++ ppriv = container_of(napi, struct dpaa2_caam_priv_per_cpu, napi);
++ priv = ppriv->priv;
++
++ if (unlikely(dpaa2_caam_pull_fq(ppriv)))
++ return 0;
++
++ do {
++ store_cleaned = dpaa2_caam_store_consume(ppriv);
++ cleaned += store_cleaned;
++
++ if (store_cleaned == 0 ||
++ cleaned > budget - DPAA2_CAAM_STORE_SIZE)
++ break;
++
++ /* Try to dequeue some more */
++ err = dpaa2_caam_pull_fq(ppriv);
++ if (unlikely(err))
++ break;
++ } while (1);
++
++ if (cleaned < budget) {
++ napi_complete_done(napi, cleaned);
++ err = dpaa2_io_service_rearm(NULL, &ppriv->nctx);
++ if (unlikely(err))
++ dev_err(priv->dev, "Notification rearm failed: %d\n",
++ err);
++ }
++
++ return cleaned;
++}
++
++static int dpaa2_dpseci_congestion_setup(struct dpaa2_caam_priv *priv,
++ u16 token)
++{
++ struct dpseci_congestion_notification_cfg cong_notif_cfg = { 0 };
++ struct device *dev = priv->dev;
++ int err;
++
++ /*
++ * Congestion group feature supported starting with DPSECI API v5.1
++ * and only when object has been created with this capability.
++ */
++ if ((DPSECI_VER(priv->major_ver, priv->minor_ver) < DPSECI_VER(5, 1)) ||
++ !(priv->dpseci_attr.options & DPSECI_OPT_HAS_CG))
++ return 0;
++
++ priv->cscn_mem = kzalloc(DPAA2_CSCN_SIZE + DPAA2_CSCN_ALIGN,
++ GFP_KERNEL | GFP_DMA);
++ if (!priv->cscn_mem)
++ return -ENOMEM;
++
++ priv->cscn_mem_aligned = PTR_ALIGN(priv->cscn_mem, DPAA2_CSCN_ALIGN);
++ priv->cscn_dma = dma_map_single(dev, priv->cscn_mem_aligned,
++ DPAA2_CSCN_SIZE, DMA_FROM_DEVICE);
++ if (dma_mapping_error(dev, priv->cscn_dma)) {
++ dev_err(dev, "Error mapping CSCN memory area\n");
++ err = -ENOMEM;
++ goto err_dma_map;
++ }
++
++ cong_notif_cfg.units = DPSECI_CONGESTION_UNIT_BYTES;
++ cong_notif_cfg.threshold_entry = DPAA2_SEC_CONG_ENTRY_THRESH;
++ cong_notif_cfg.threshold_exit = DPAA2_SEC_CONG_EXIT_THRESH;
++ cong_notif_cfg.message_ctx = (u64)priv;
++ cong_notif_cfg.message_iova = priv->cscn_dma;
++ cong_notif_cfg.notification_mode = DPSECI_CGN_MODE_WRITE_MEM_ON_ENTER |
++ DPSECI_CGN_MODE_WRITE_MEM_ON_EXIT |
++ DPSECI_CGN_MODE_COHERENT_WRITE;
++
++ err = dpseci_set_congestion_notification(priv->mc_io, 0, token,
++ &cong_notif_cfg);
++ if (err) {
++ dev_err(dev, "dpseci_set_congestion_notification failed\n");
++ goto err_set_cong;
++ }
++
++ return 0;
++
++err_set_cong:
++ dma_unmap_single(dev, priv->cscn_dma, DPAA2_CSCN_SIZE, DMA_FROM_DEVICE);
++err_dma_map:
++ kfree(priv->cscn_mem);
++
++ return err;
++}
++
++static int __cold dpaa2_dpseci_setup(struct fsl_mc_device *ls_dev)
++{
++ struct device *dev = &ls_dev->dev;
++ struct dpaa2_caam_priv *priv;
++ struct dpaa2_caam_priv_per_cpu *ppriv;
++ int err, cpu;
++ u8 i;
++
++ priv = dev_get_drvdata(dev);
++
++ priv->dev = dev;
++ priv->dpsec_id = ls_dev->obj_desc.id;
++
++ /* Get a handle for the DPSECI this interface is associate with */
++ err = dpseci_open(priv->mc_io, 0, priv->dpsec_id, &ls_dev->mc_handle);
++ if (err) {
++ dev_err(dev, "dpsec_open() failed: %d\n", err);
++ goto err_open;
++ }
++
++ dev_info(dev, "Opened dpseci object successfully\n");
++
++ err = dpseci_get_api_version(priv->mc_io, 0, &priv->major_ver,
++ &priv->minor_ver);
++ if (err) {
++ dev_err(dev, "dpseci_get_api_version() failed\n");
++ goto err_get_vers;
++ }
++
++ err = dpseci_get_attributes(priv->mc_io, 0, ls_dev->mc_handle,
++ &priv->dpseci_attr);
++ if (err) {
++ dev_err(dev, "dpseci_get_attributes() failed\n");
++ goto err_get_vers;
++ }
++
++ err = dpseci_get_sec_attr(priv->mc_io, 0, ls_dev->mc_handle,
++ &priv->sec_attr);
++ if (err) {
++ dev_err(dev, "dpseci_get_sec_attr() failed\n");
++ goto err_get_vers;
++ }
++
++ err = dpaa2_dpseci_congestion_setup(priv, ls_dev->mc_handle);
++ if (err) {
++ dev_err(dev, "setup_congestion() failed\n");
++ goto err_get_vers;
++ }
++
++ priv->num_pairs = min(priv->dpseci_attr.num_rx_queues,
++ priv->dpseci_attr.num_tx_queues);
++ if (priv->num_pairs > num_online_cpus()) {
++ dev_warn(dev, "%d queues won't be used\n",
++ priv->num_pairs - num_online_cpus());
++ priv->num_pairs = num_online_cpus();
++ }
++
++ for (i = 0; i < priv->dpseci_attr.num_rx_queues; i++) {
++ err = dpseci_get_rx_queue(priv->mc_io, 0, ls_dev->mc_handle, i,
++ &priv->rx_queue_attr[i]);
++ if (err) {
++ dev_err(dev, "dpseci_get_rx_queue() failed\n");
++ goto err_get_rx_queue;
++ }
++ }
++
++ for (i = 0; i < priv->dpseci_attr.num_tx_queues; i++) {
++ err = dpseci_get_tx_queue(priv->mc_io, 0, ls_dev->mc_handle, i,
++ &priv->tx_queue_attr[i]);
++ if (err) {
++ dev_err(dev, "dpseci_get_tx_queue() failed\n");
++ goto err_get_rx_queue;
++ }
++ }
++
++ i = 0;
++ for_each_online_cpu(cpu) {
++ dev_info(dev, "pair %d: rx queue %d, tx queue %d\n", i,
++ priv->rx_queue_attr[i].fqid,
++ priv->tx_queue_attr[i].fqid);
++
++ ppriv = per_cpu_ptr(priv->ppriv, cpu);
++ ppriv->req_fqid = priv->tx_queue_attr[i].fqid;
++ ppriv->rsp_fqid = priv->rx_queue_attr[i].fqid;
++ ppriv->prio = i;
++
++ ppriv->net_dev.dev = *dev;
++ INIT_LIST_HEAD(&ppriv->net_dev.napi_list);
++ netif_napi_add(&ppriv->net_dev, &ppriv->napi, dpaa2_dpseci_poll,
++ DPAA2_CAAM_NAPI_WEIGHT);
++ if (++i == priv->num_pairs)
++ break;
++ }
++
++ return 0;
++
++err_get_rx_queue:
++ dpaa2_dpseci_congestion_free(priv);
++err_get_vers:
++ dpseci_close(priv->mc_io, 0, ls_dev->mc_handle);
++err_open:
++ return err;
++}
++
++static int dpaa2_dpseci_enable(struct dpaa2_caam_priv *priv)
++{
++ struct device *dev = priv->dev;
++ struct fsl_mc_device *ls_dev = to_fsl_mc_device(dev);
++ struct dpaa2_caam_priv_per_cpu *ppriv;
++ int err, i;
++
++ for (i = 0; i < priv->num_pairs; i++) {
++ ppriv = per_cpu_ptr(priv->ppriv, i);
++ napi_enable(&ppriv->napi);
++ }
++
++ err = dpseci_enable(priv->mc_io, 0, ls_dev->mc_handle);
++ if (err) {
++ dev_err(dev, "dpseci_enable() failed\n");
++ return err;
++ }
++
++ dev_info(dev, "DPSECI version %d.%d\n",
++ priv->major_ver,
++ priv->minor_ver);
++
++ return 0;
++}
++
++static int __cold dpaa2_dpseci_disable(struct dpaa2_caam_priv *priv)
++{
++ struct device *dev = priv->dev;
++ struct dpaa2_caam_priv_per_cpu *ppriv;
++ struct fsl_mc_device *ls_dev = to_fsl_mc_device(dev);
++ int i, err = 0, enabled;
++
++ err = dpseci_disable(priv->mc_io, 0, ls_dev->mc_handle);
++ if (err) {
++ dev_err(dev, "dpseci_disable() failed\n");
++ return err;
++ }
++
++ err = dpseci_is_enabled(priv->mc_io, 0, ls_dev->mc_handle, &enabled);
++ if (err) {
++ dev_err(dev, "dpseci_is_enabled() failed\n");
++ return err;
++ }
++
++ dev_dbg(dev, "disable: %s\n", enabled ? "false" : "true");
++
++ for (i = 0; i < priv->num_pairs; i++) {
++ ppriv = per_cpu_ptr(priv->ppriv, i);
++ napi_disable(&ppriv->napi);
++ netif_napi_del(&ppriv->napi);
++ }
++
++ return 0;
++}
++
++static struct list_head hash_list;
++
++static int dpaa2_caam_probe(struct fsl_mc_device *dpseci_dev)
++{
++ struct device *dev;
++ struct dpaa2_caam_priv *priv;
++ int i, err = 0;
++ bool registered = false;
++
++ /*
++ * There is no way to get CAAM endianness - there is no direct register
++ * space access and MC f/w does not provide this attribute.
++ * All DPAA2-based SoCs have little endian CAAM, thus hard-code this
++ * property.
++ */
++ caam_little_end = true;
++
++ caam_imx = false;
++
++ dev = &dpseci_dev->dev;
++
++ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ dev_set_drvdata(dev, priv);
++
++ priv->domain = iommu_get_domain_for_dev(dev);
++
++ qi_cache = kmem_cache_create("dpaa2_caamqicache", CAAM_QI_MEMCACHE_SIZE,
++ 0, SLAB_CACHE_DMA, NULL);
++ if (!qi_cache) {
++ dev_err(dev, "Can't allocate SEC cache\n");
++ err = -ENOMEM;
++ goto err_qicache;
++ }
++
++ err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(49));
++ if (err) {
++ dev_err(dev, "dma_set_mask_and_coherent() failed\n");
++ goto err_dma_mask;
++ }
++
++ /* Obtain a MC portal */
++ err = fsl_mc_portal_allocate(dpseci_dev, 0, &priv->mc_io);
++ if (err) {
++ if (err == -ENXIO)
++ err = -EPROBE_DEFER;
++ else
++ dev_err(dev, "MC portal allocation failed\n");
++
++ goto err_dma_mask;
++ }
++
++ priv->ppriv = alloc_percpu(*priv->ppriv);
++ if (!priv->ppriv) {
++ dev_err(dev, "alloc_percpu() failed\n");
++ goto err_alloc_ppriv;
++ }
++
++ /* DPSECI initialization */
++ err = dpaa2_dpseci_setup(dpseci_dev);
++ if (err < 0) {
++ dev_err(dev, "dpaa2_dpseci_setup() failed\n");
++ goto err_dpseci_setup;
++ }
++
++ /* DPIO */
++ err = dpaa2_dpseci_dpio_setup(priv);
++ if (err) {
++ dev_err(dev, "dpaa2_dpseci_dpio_setup() failed\n");
++ goto err_dpio_setup;
++ }
++
++ /* DPSECI binding to DPIO */
++ err = dpaa2_dpseci_bind(priv);
++ if (err) {
++ dev_err(dev, "dpaa2_dpseci_bind() failed\n");
++ goto err_bind;
++ }
++
++ /* DPSECI enable */
++ err = dpaa2_dpseci_enable(priv);
++ if (err) {
++ dev_err(dev, "dpaa2_dpseci_enable() failed");
++ goto err_bind;
++ }
++
++ /* register crypto algorithms the device supports */
++ for (i = 0; i < ARRAY_SIZE(driver_algs); i++) {
++ struct caam_skcipher_alg *t_alg = driver_algs + i;
++ u32 alg_sel = t_alg->caam.class1_alg_type & OP_ALG_ALGSEL_MASK;
++
++ /* Skip DES algorithms if not supported by device */
++ if (!priv->sec_attr.des_acc_num &&
++ ((alg_sel == OP_ALG_ALGSEL_3DES) ||
++ (alg_sel == OP_ALG_ALGSEL_DES)))
++ continue;
++
++ /* Skip AES algorithms if not supported by device */
++ if (!priv->sec_attr.aes_acc_num &&
++ (alg_sel == OP_ALG_ALGSEL_AES))
++ continue;
++
++ t_alg->caam.dev = dev;
++ caam_skcipher_alg_init(t_alg);
++
++ err = crypto_register_skcipher(&t_alg->skcipher);
++ if (err) {
++ dev_warn(dev, "%s alg registration failed: %d\n",
++ t_alg->skcipher.base.cra_driver_name, err);
++ continue;
++ }
++
++ t_alg->registered = true;
++ registered = true;
++ }
++
++ for (i = 0; i < ARRAY_SIZE(driver_aeads); i++) {
++ struct caam_aead_alg *t_alg = driver_aeads + i;
++ u32 c1_alg_sel = t_alg->caam.class1_alg_type &
++ OP_ALG_ALGSEL_MASK;
++ u32 c2_alg_sel = t_alg->caam.class2_alg_type &
++ OP_ALG_ALGSEL_MASK;
++
++ /* Skip DES algorithms if not supported by device */
++ if (!priv->sec_attr.des_acc_num &&
++ ((c1_alg_sel == OP_ALG_ALGSEL_3DES) ||
++ (c1_alg_sel == OP_ALG_ALGSEL_DES)))
++ continue;
++
++ /* Skip AES algorithms if not supported by device */
++ if (!priv->sec_attr.aes_acc_num &&
++ (c1_alg_sel == OP_ALG_ALGSEL_AES))
++ continue;
++
++ /*
++ * Skip algorithms requiring message digests
++ * if MD not supported by device.
++ */
++ if (!priv->sec_attr.md_acc_num && c2_alg_sel)
++ continue;
++
++ t_alg->caam.dev = dev;
++ caam_aead_alg_init(t_alg);
++
++ err = crypto_register_aead(&t_alg->aead);
++ if (err) {
++ dev_warn(dev, "%s alg registration failed: %d\n",
++ t_alg->aead.base.cra_driver_name, err);
++ continue;
++ }
++
++ t_alg->registered = true;
++ registered = true;
++ }
++ if (registered)
++ dev_info(dev, "algorithms registered in /proc/crypto\n");
++
++ /* register hash algorithms the device supports */
++ INIT_LIST_HEAD(&hash_list);
++
++ /*
++ * Skip registration of any hashing algorithms if MD block
++ * is not present.
++ */
++ if (!priv->sec_attr.md_acc_num)
++ return 0;
++
++ for (i = 0; i < ARRAY_SIZE(driver_hash); i++) {
++ struct caam_hash_alg *t_alg;
++ struct caam_hash_template *alg = driver_hash + i;
++
++ /* register hmac version */
++ t_alg = caam_hash_alloc(dev, alg, true);
++ if (IS_ERR(t_alg)) {
++ err = PTR_ERR(t_alg);
++ dev_warn(dev, "%s hash alg allocation failed: %d\n",
++ alg->driver_name, err);
++ continue;
++ }
++
++ err = crypto_register_ahash(&t_alg->ahash_alg);
++ if (err) {
++ dev_warn(dev, "%s alg registration failed: %d\n",
++ t_alg->ahash_alg.halg.base.cra_driver_name,
++ err);
++ kfree(t_alg);
++ } else {
++ list_add_tail(&t_alg->entry, &hash_list);
++ }
++
++ /* register unkeyed version */
++ t_alg = caam_hash_alloc(dev, alg, false);
++ if (IS_ERR(t_alg)) {
++ err = PTR_ERR(t_alg);
++ dev_warn(dev, "%s alg allocation failed: %d\n",
++ alg->driver_name, err);
++ continue;
++ }
++
++ err = crypto_register_ahash(&t_alg->ahash_alg);
++ if (err) {
++ dev_warn(dev, "%s alg registration failed: %d\n",
++ t_alg->ahash_alg.halg.base.cra_driver_name,
++ err);
++ kfree(t_alg);
++ } else {
++ list_add_tail(&t_alg->entry, &hash_list);
++ }
++ }
++ if (!list_empty(&hash_list))
++ dev_info(dev, "hash algorithms registered in /proc/crypto\n");
++
++ return err;
++
++err_bind:
++ dpaa2_dpseci_dpio_free(priv);
++err_dpio_setup:
++ dpaa2_dpseci_free(priv);
++err_dpseci_setup:
++ free_percpu(priv->ppriv);
++err_alloc_ppriv:
++ fsl_mc_portal_free(priv->mc_io);
++err_dma_mask:
++ kmem_cache_destroy(qi_cache);
++err_qicache:
++ dev_set_drvdata(dev, NULL);
++
++ return err;
++}
++
++static int __cold dpaa2_caam_remove(struct fsl_mc_device *ls_dev)
++{
++ struct device *dev;
++ struct dpaa2_caam_priv *priv;
++ int i;
++
++ dev = &ls_dev->dev;
++ priv = dev_get_drvdata(dev);
++
++ for (i = 0; i < ARRAY_SIZE(driver_aeads); i++) {
++ struct caam_aead_alg *t_alg = driver_aeads + i;
++
++ if (t_alg->registered)
++ crypto_unregister_aead(&t_alg->aead);
++ }
++
++ for (i = 0; i < ARRAY_SIZE(driver_algs); i++) {
++ struct caam_skcipher_alg *t_alg = driver_algs + i;
++
++ if (t_alg->registered)
++ crypto_unregister_skcipher(&t_alg->skcipher);
++ }
++
++ if (hash_list.next) {
++ struct caam_hash_alg *t_hash_alg, *p;
++
++ list_for_each_entry_safe(t_hash_alg, p, &hash_list, entry) {
++ crypto_unregister_ahash(&t_hash_alg->ahash_alg);
++ list_del(&t_hash_alg->entry);
++ kfree(t_hash_alg);
++ }
++ }
++
++ dpaa2_dpseci_disable(priv);
++ dpaa2_dpseci_dpio_free(priv);
++ dpaa2_dpseci_free(priv);
++ free_percpu(priv->ppriv);
++ fsl_mc_portal_free(priv->mc_io);
++ dev_set_drvdata(dev, NULL);
++ kmem_cache_destroy(qi_cache);
++
++ return 0;
++}
++
++int dpaa2_caam_enqueue(struct device *dev, struct caam_request *req)
++{
++ struct dpaa2_fd fd;
++ struct dpaa2_caam_priv *priv = dev_get_drvdata(dev);
++ int err = 0, i, id;
++
++ if (IS_ERR(req))
++ return PTR_ERR(req);
++
++ if (priv->cscn_mem) {
++ dma_sync_single_for_cpu(priv->dev, priv->cscn_dma,
++ DPAA2_CSCN_SIZE,
++ DMA_FROM_DEVICE);
++ if (unlikely(dpaa2_cscn_state_congested(priv->cscn_mem_aligned))) {
++ dev_dbg_ratelimited(dev, "Dropping request\n");
++ return -EBUSY;
++ }
++ }
++
++ dpaa2_fl_set_flc(&req->fd_flt[1], req->flc_dma);
++
++ req->fd_flt_dma = dma_map_single(dev, req->fd_flt, sizeof(req->fd_flt),
++ DMA_BIDIRECTIONAL);
++ if (dma_mapping_error(dev, req->fd_flt_dma)) {
++ dev_err(dev, "DMA mapping error for QI enqueue request\n");
++ goto err_out;
++ }
++
++ memset(&fd, 0, sizeof(fd));
++ dpaa2_fd_set_format(&fd, dpaa2_fd_list);
++ dpaa2_fd_set_addr(&fd, req->fd_flt_dma);
++ dpaa2_fd_set_len(&fd, dpaa2_fl_get_len(&req->fd_flt[1]));
++ dpaa2_fd_set_flc(&fd, req->flc_dma);
++
++ /*
++ * There is no guarantee that preemption is disabled here,
++ * thus take action.
++ */
++ preempt_disable();
++ id = smp_processor_id() % priv->dpseci_attr.num_tx_queues;
++ for (i = 0; i < (priv->dpseci_attr.num_tx_queues << 1); i++) {
++ err = dpaa2_io_service_enqueue_fq(NULL,
++ priv->tx_queue_attr[id].fqid,
++ &fd);
++ if (err != -EBUSY)
++ break;
++ }
++ preempt_enable();
++
++ if (unlikely(err < 0)) {
++ dev_err(dev, "Error enqueuing frame: %d\n", err);
++ goto err_out;
++ }
++
++ return -EINPROGRESS;
++
++err_out:
++ dma_unmap_single(dev, req->fd_flt_dma, sizeof(req->fd_flt),
++ DMA_BIDIRECTIONAL);
++ return -EIO;
++}
++EXPORT_SYMBOL(dpaa2_caam_enqueue);
++
++const struct fsl_mc_device_id dpaa2_caam_match_id_table[] = {
++ {
++ .vendor = FSL_MC_VENDOR_FREESCALE,
++ .obj_type = "dpseci",
++ },
++ { .vendor = 0x0 }
++};
++
++static struct fsl_mc_driver dpaa2_caam_driver = {
++ .driver = {
++ .name = KBUILD_MODNAME,
++ .owner = THIS_MODULE,
++ },
++ .probe = dpaa2_caam_probe,
++ .remove = dpaa2_caam_remove,
++ .match_id_table = dpaa2_caam_match_id_table
++};
++
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_AUTHOR("Freescale Semiconductor, Inc");
++MODULE_DESCRIPTION("Freescale DPAA2 CAAM Driver");
++
++module_fsl_mc_driver(dpaa2_caam_driver);
+--- /dev/null
++++ b/drivers/crypto/caam/caamalg_qi2.h
+@@ -0,0 +1,274 @@
++/*
++ * Copyright 2015-2016 Freescale Semiconductor Inc.
++ * Copyright 2017 NXP
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * * Neither the names of the above-listed copyright holders nor the
++ * names of any contributors may be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _CAAMALG_QI2_H_
++#define _CAAMALG_QI2_H_
++
++#include "../../../drivers/staging/fsl-mc/include/dpaa2-io.h"
++#include "../../../drivers/staging/fsl-mc/include/dpaa2-fd.h"
++#include <linux/threads.h>
++#include "dpseci.h"
++#include "desc_constr.h"
++
++#define DPAA2_CAAM_STORE_SIZE 16
++/* NAPI weight *must* be a multiple of the store size. */
++#define DPAA2_CAAM_NAPI_WEIGHT 64
++
++/* The congestion entrance threshold was chosen so that on LS2088
++ * we support the maximum throughput for the available memory
++ */
++#define DPAA2_SEC_CONG_ENTRY_THRESH (128 * 1024 * 1024)
++#define DPAA2_SEC_CONG_EXIT_THRESH (DPAA2_SEC_CONG_ENTRY_THRESH * 9 / 10)
++
++/**
++ * dpaa2_caam_priv - driver private data
++ * @dpseci_id: DPSECI object unique ID
++ * @major_ver: DPSECI major version
++ * @minor_ver: DPSECI minor version
++ * @dpseci_attr: DPSECI attributes
++ * @sec_attr: SEC engine attributes
++ * @rx_queue_attr: array of Rx queue attributes
++ * @tx_queue_attr: array of Tx queue attributes
++ * @cscn_mem: pointer to memory region containing the
++ * dpaa2_cscn struct; it's size is larger than
++ * sizeof(struct dpaa2_cscn) to accommodate alignment
++ * @cscn_mem_aligned: pointer to struct dpaa2_cscn; it is computed
++ * as PTR_ALIGN(cscn_mem, DPAA2_CSCN_ALIGN)
++ * @cscn_dma: dma address used by the QMAN to write CSCN messages
++ * @dev: device associated with the DPSECI object
++ * @mc_io: pointer to MC portal's I/O object
++ * @domain: IOMMU domain
++ * @ppriv: per CPU pointers to privata data
++ */
++struct dpaa2_caam_priv {
++ int dpsec_id;
++
++ u16 major_ver;
++ u16 minor_ver;
++
++ struct dpseci_attr dpseci_attr;
++ struct dpseci_sec_attr sec_attr;
++ struct dpseci_rx_queue_attr rx_queue_attr[DPSECI_MAX_QUEUE_NUM];
++ struct dpseci_tx_queue_attr tx_queue_attr[DPSECI_MAX_QUEUE_NUM];
++ int num_pairs;
++
++ /* congestion */
++ void *cscn_mem;
++ void *cscn_mem_aligned;
++ dma_addr_t cscn_dma;
++
++ struct device *dev;
++ struct fsl_mc_io *mc_io;
++ struct iommu_domain *domain;
++
++ struct dpaa2_caam_priv_per_cpu __percpu *ppriv;
++};
++
++/**
++ * dpaa2_caam_priv_per_cpu - per CPU private data
++ * @napi: napi structure
++ * @net_dev: netdev used by napi
++ * @req_fqid: (virtual) request (Tx / enqueue) FQID
++ * @rsp_fqid: (virtual) response (Rx / dequeue) FQID
++ * @prio: internal queue number - index for dpaa2_caam_priv.*_queue_attr
++ * @nctx: notification context of response FQ
++ * @store: where dequeued frames are stored
++ * @priv: backpointer to dpaa2_caam_priv
++ */
++struct dpaa2_caam_priv_per_cpu {
++ struct napi_struct napi;
++ struct net_device net_dev;
++ int req_fqid;
++ int rsp_fqid;
++ int prio;
++ struct dpaa2_io_notification_ctx nctx;
++ struct dpaa2_io_store *store;
++ struct dpaa2_caam_priv *priv;
++};
++
++/*
++ * The CAAM QI hardware constructs a job descriptor which points
++ * to shared descriptor (as pointed by context_a of FQ to CAAM).
++ * When the job descriptor is executed by deco, the whole job
++ * descriptor together with shared descriptor gets loaded in
++ * deco buffer which is 64 words long (each 32-bit).
++ *
++ * The job descriptor constructed by QI hardware has layout:
++ *
++ * HEADER (1 word)
++ * Shdesc ptr (1 or 2 words)
++ * SEQ_OUT_PTR (1 word)
++ * Out ptr (1 or 2 words)
++ * Out length (1 word)
++ * SEQ_IN_PTR (1 word)
++ * In ptr (1 or 2 words)
++ * In length (1 word)
++ *
++ * The shdesc ptr is used to fetch shared descriptor contents
++ * into deco buffer.
++ *
++ * Apart from shdesc contents, the total number of words that
++ * get loaded in deco buffer are '8' or '11'. The remaining words
++ * in deco buffer can be used for storing shared descriptor.
++ */
++#define MAX_SDLEN ((CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN) / CAAM_CMD_SZ)
++
++/* Length of a single buffer in the QI driver memory cache */
++#define CAAM_QI_MEMCACHE_SIZE 512
++
++/*
++ * aead_edesc - s/w-extended aead descriptor
++ * @src_nents: number of segments in input scatterlist
++ * @dst_nents: number of segments in output scatterlist
++ * @iv_dma: dma address of iv for checking continuity and link table
++ * @qm_sg_bytes: length of dma mapped h/w link table
++ * @qm_sg_dma: bus physical mapped address of h/w link table
++ * @assoclen: associated data length, in CAAM endianness
++ * @assoclen_dma: bus physical mapped address of req->assoclen
++ * @sgt: the h/w link table, followed by IV
++ */
++struct aead_edesc {
++ int src_nents;
++ int dst_nents;
++ dma_addr_t iv_dma;
++ int qm_sg_bytes;
++ dma_addr_t qm_sg_dma;
++ unsigned int assoclen;
++ dma_addr_t assoclen_dma;
++ struct dpaa2_sg_entry sgt[0];
++};
++
++/*
++ * tls_edesc - s/w-extended tls descriptor
++ * @src_nents: number of segments in input scatterlist
++ * @dst_nents: number of segments in output scatterlist
++ * @iv_dma: dma address of iv for checking continuity and link table
++ * @qm_sg_bytes: length of dma mapped h/w link table
++ * @qm_sg_dma: bus physical mapped address of h/w link table
++ * @tmp: array of scatterlists used by 'scatterwalk_ffwd'
++ * @dst: pointer to output scatterlist, usefull for unmapping
++ * @sgt: the h/w link table, followed by IV
++ */
++struct tls_edesc {
++ int src_nents;
++ int dst_nents;
++ dma_addr_t iv_dma;
++ int qm_sg_bytes;
++ dma_addr_t qm_sg_dma;
++ struct scatterlist tmp[2];
++ struct scatterlist *dst;
++ struct dpaa2_sg_entry sgt[0];
++};
++
++/*
++ * skcipher_edesc - s/w-extended skcipher descriptor
++ * @src_nents: number of segments in input scatterlist
++ * @dst_nents: number of segments in output scatterlist
++ * @iv_dma: dma address of iv for checking continuity and link table
++ * @qm_sg_bytes: length of dma mapped qm_sg space
++ * @qm_sg_dma: I/O virtual address of h/w link table
++ * @sgt: the h/w link table, followed by IV
++ */
++struct skcipher_edesc {
++ int src_nents;
++ int dst_nents;
++ dma_addr_t iv_dma;
++ int qm_sg_bytes;
++ dma_addr_t qm_sg_dma;
++ struct dpaa2_sg_entry sgt[0];
++};
++
++/*
++ * ahash_edesc - s/w-extended ahash descriptor
++ * @dst_dma: I/O virtual address of req->result
++ * @qm_sg_dma: I/O virtual address of h/w link table
++ * @src_nents: number of segments in input scatterlist
++ * @qm_sg_bytes: length of dma mapped qm_sg space
++ * @sgt: pointer to h/w link table
++ */
++struct ahash_edesc {
++ dma_addr_t dst_dma;
++ dma_addr_t qm_sg_dma;
++ int src_nents;
++ int qm_sg_bytes;
++ struct dpaa2_sg_entry sgt[0];
++};
++
++/**
++ * caam_flc - Flow Context (FLC)
++ * @flc: Flow Context options
++ * @sh_desc: Shared Descriptor
++ */
++struct caam_flc {
++ u32 flc[16];
++ u32 sh_desc[MAX_SDLEN];
++} ____cacheline_aligned;
++
++enum optype {
++ ENCRYPT = 0,
++ DECRYPT,
++ NUM_OP
++};
++
++/**
++ * caam_request - the request structure the driver application should fill while
++ * submitting a job to driver.
++ * @fd_flt: Frame list table defining input and output
++ * fd_flt[0] - FLE pointing to output buffer
++ * fd_flt[1] - FLE pointing to input buffer
++ * @fd_flt_dma: DMA address for the frame list table
++ * @flc: Flow Context
++ * @flc_dma: I/O virtual address of Flow Context
++ * @cbk: Callback function to invoke when job is completed
++ * @ctx: arbit context attached with request by the application
++ * @edesc: extended descriptor; points to one of {skcipher,aead}_edesc
++ */
++struct caam_request {
++ struct dpaa2_fl_entry fd_flt[2];
++ dma_addr_t fd_flt_dma;
++ struct caam_flc *flc;
++ dma_addr_t flc_dma;
++ void (*cbk)(void *ctx, u32 err);
++ void *ctx;
++ void *edesc;
++};
++
++/**
++ * dpaa2_caam_enqueue() - enqueue a crypto request
++ * @dev: device associated with the DPSECI object
++ * @req: pointer to caam_request
++ */
++int dpaa2_caam_enqueue(struct device *dev, struct caam_request *req);
++
++#endif /* _CAAMALG_QI2_H_ */
+--- a/drivers/crypto/caam/caamhash.c
++++ b/drivers/crypto/caam/caamhash.c
+@@ -62,6 +62,7 @@
+ #include "error.h"
+ #include "sg_sw_sec4.h"
+ #include "key_gen.h"
++#include "caamhash_desc.h"
+
+ #define CAAM_CRA_PRIORITY 3000
+
+@@ -71,14 +72,6 @@
+ #define CAAM_MAX_HASH_BLOCK_SIZE SHA512_BLOCK_SIZE
+ #define CAAM_MAX_HASH_DIGEST_SIZE SHA512_DIGEST_SIZE
+
+-/* length of descriptors text */
+-#define DESC_AHASH_BASE (3 * CAAM_CMD_SZ)
+-#define DESC_AHASH_UPDATE_LEN (6 * CAAM_CMD_SZ)
+-#define DESC_AHASH_UPDATE_FIRST_LEN (DESC_AHASH_BASE + 4 * CAAM_CMD_SZ)
+-#define DESC_AHASH_FINAL_LEN (DESC_AHASH_BASE + 5 * CAAM_CMD_SZ)
+-#define DESC_AHASH_FINUP_LEN (DESC_AHASH_BASE + 5 * CAAM_CMD_SZ)
+-#define DESC_AHASH_DIGEST_LEN (DESC_AHASH_BASE + 4 * CAAM_CMD_SZ)
+-
+ #define DESC_HASH_MAX_USED_BYTES (DESC_AHASH_FINAL_LEN + \
+ CAAM_MAX_HASH_KEY_SIZE)
+ #define DESC_HASH_MAX_USED_LEN (DESC_HASH_MAX_USED_BYTES / CAAM_CMD_SZ)
+@@ -107,6 +100,7 @@ struct caam_hash_ctx {
+ dma_addr_t sh_desc_update_first_dma;
+ dma_addr_t sh_desc_fin_dma;
+ dma_addr_t sh_desc_digest_dma;
++ enum dma_data_direction dir;
+ struct device *jrdev;
+ u8 key[CAAM_MAX_HASH_KEY_SIZE];
+ int ctx_len;
+@@ -218,7 +212,7 @@ static inline int buf_map_to_sec4_sg(str
+ }
+
+ /* Map state->caam_ctx, and add it to link table */
+-static inline int ctx_map_to_sec4_sg(u32 *desc, struct device *jrdev,
++static inline int ctx_map_to_sec4_sg(struct device *jrdev,
+ struct caam_hash_state *state, int ctx_len,
+ struct sec4_sg_entry *sec4_sg, u32 flag)
+ {
+@@ -234,68 +228,22 @@ static inline int ctx_map_to_sec4_sg(u32
+ return 0;
+ }
+
+-/*
+- * For ahash update, final and finup (import_ctx = true)
+- * import context, read and write to seqout
+- * For ahash firsts and digest (import_ctx = false)
+- * read and write to seqout
+- */
+-static inline void ahash_gen_sh_desc(u32 *desc, u32 state, int digestsize,
+- struct caam_hash_ctx *ctx, bool import_ctx)
+-{
+- u32 op = ctx->adata.algtype;
+- u32 *skip_key_load;
+-
+- init_sh_desc(desc, HDR_SHARE_SERIAL);
+-
+- /* Append key if it has been set; ahash update excluded */
+- if ((state != OP_ALG_AS_UPDATE) && (ctx->adata.keylen)) {
+- /* Skip key loading if already shared */
+- skip_key_load = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
+- JUMP_COND_SHRD);
+-
+- append_key_as_imm(desc, ctx->key, ctx->adata.keylen_pad,
+- ctx->adata.keylen, CLASS_2 |
+- KEY_DEST_MDHA_SPLIT | KEY_ENC);
+-
+- set_jump_tgt_here(desc, skip_key_load);
+-
+- op |= OP_ALG_AAI_HMAC_PRECOMP;
+- }
+-
+- /* If needed, import context from software */
+- if (import_ctx)
+- append_seq_load(desc, ctx->ctx_len, LDST_CLASS_2_CCB |
+- LDST_SRCDST_BYTE_CONTEXT);
+-
+- /* Class 2 operation */
+- append_operation(desc, op | state | OP_ALG_ENCRYPT);
+-
+- /*
+- * Load from buf and/or src and write to req->result or state->context
+- * Calculate remaining bytes to read
+- */
+- append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ);
+- /* Read remaining bytes */
+- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_LAST2 |
+- FIFOLD_TYPE_MSG | KEY_VLF);
+- /* Store class2 context bytes */
+- append_seq_store(desc, digestsize, LDST_CLASS_2_CCB |
+- LDST_SRCDST_BYTE_CONTEXT);
+-}
+-
+ static int ahash_set_sh_desc(struct crypto_ahash *ahash)
+ {
+ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+ int digestsize = crypto_ahash_digestsize(ahash);
+ struct device *jrdev = ctx->jrdev;
++ struct caam_drv_private *ctrlpriv = dev_get_drvdata(jrdev->parent);
+ u32 *desc;
+
++ ctx->adata.key_virt = ctx->key;
++
+ /* ahash_update shared descriptor */
+ desc = ctx->sh_desc_update;
+- ahash_gen_sh_desc(desc, OP_ALG_AS_UPDATE, ctx->ctx_len, ctx, true);
++ cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_UPDATE, ctx->ctx_len,
++ ctx->ctx_len, true, ctrlpriv->era);
+ dma_sync_single_for_device(jrdev, ctx->sh_desc_update_dma,
+- desc_bytes(desc), DMA_TO_DEVICE);
++ desc_bytes(desc), ctx->dir);
+ #ifdef DEBUG
+ print_hex_dump(KERN_ERR,
+ "ahash update shdesc@"__stringify(__LINE__)": ",
+@@ -304,9 +252,10 @@ static int ahash_set_sh_desc(struct cryp
+
+ /* ahash_update_first shared descriptor */
+ desc = ctx->sh_desc_update_first;
+- ahash_gen_sh_desc(desc, OP_ALG_AS_INIT, ctx->ctx_len, ctx, false);
++ cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_INIT, ctx->ctx_len,
++ ctx->ctx_len, false, ctrlpriv->era);
+ dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma,
+- desc_bytes(desc), DMA_TO_DEVICE);
++ desc_bytes(desc), ctx->dir);
+ #ifdef DEBUG
+ print_hex_dump(KERN_ERR,
+ "ahash update first shdesc@"__stringify(__LINE__)": ",
+@@ -315,9 +264,10 @@ static int ahash_set_sh_desc(struct cryp
+
+ /* ahash_final shared descriptor */
+ desc = ctx->sh_desc_fin;
+- ahash_gen_sh_desc(desc, OP_ALG_AS_FINALIZE, digestsize, ctx, true);
++ cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_FINALIZE, digestsize,
++ ctx->ctx_len, true, ctrlpriv->era);
+ dma_sync_single_for_device(jrdev, ctx->sh_desc_fin_dma,
+- desc_bytes(desc), DMA_TO_DEVICE);
++ desc_bytes(desc), ctx->dir);
+ #ifdef DEBUG
+ print_hex_dump(KERN_ERR, "ahash final shdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc,
+@@ -326,9 +276,10 @@ static int ahash_set_sh_desc(struct cryp
+
+ /* ahash_digest shared descriptor */
+ desc = ctx->sh_desc_digest;
+- ahash_gen_sh_desc(desc, OP_ALG_AS_INITFINAL, digestsize, ctx, false);
++ cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_INITFINAL, digestsize,
++ ctx->ctx_len, false, ctrlpriv->era);
+ dma_sync_single_for_device(jrdev, ctx->sh_desc_digest_dma,
+- desc_bytes(desc), DMA_TO_DEVICE);
++ desc_bytes(desc), ctx->dir);
+ #ifdef DEBUG
+ print_hex_dump(KERN_ERR,
+ "ahash digest shdesc@"__stringify(__LINE__)": ",
+@@ -421,6 +372,7 @@ static int ahash_setkey(struct crypto_ah
+ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+ int blocksize = crypto_tfm_alg_blocksize(&ahash->base);
+ int digestsize = crypto_ahash_digestsize(ahash);
++ struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctx->jrdev->parent);
+ int ret;
+ u8 *hashed_key = NULL;
+
+@@ -441,16 +393,26 @@ static int ahash_setkey(struct crypto_ah
+ key = hashed_key;
+ }
+
+- ret = gen_split_key(ctx->jrdev, ctx->key, &ctx->adata, key, keylen,
+- CAAM_MAX_HASH_KEY_SIZE);
+- if (ret)
+- goto bad_free_key;
++ /*
++ * If DKP is supported, use it in the shared descriptor to generate
++ * the split key.
++ */
++ if (ctrlpriv->era >= 6) {
++ ctx->adata.key_inline = true;
++ ctx->adata.keylen = keylen;
++ ctx->adata.keylen_pad = split_key_len(ctx->adata.algtype &
++ OP_ALG_ALGSEL_MASK);
+
+-#ifdef DEBUG
+- print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ",
+- DUMP_PREFIX_ADDRESS, 16, 4, ctx->key,
+- ctx->adata.keylen_pad, 1);
+-#endif
++ if (ctx->adata.keylen_pad > CAAM_MAX_HASH_KEY_SIZE)
++ goto bad_free_key;
++
++ memcpy(ctx->key, key, keylen);
++ } else {
++ ret = gen_split_key(ctx->jrdev, ctx->key, &ctx->adata, key,
++ keylen, CAAM_MAX_HASH_KEY_SIZE);
++ if (ret)
++ goto bad_free_key;
++ }
+
+ kfree(hashed_key);
+ return ahash_set_sh_desc(ahash);
+@@ -773,7 +735,7 @@ static int ahash_update_ctx(struct ahash
+ edesc->src_nents = src_nents;
+ edesc->sec4_sg_bytes = sec4_sg_bytes;
+
+- ret = ctx_map_to_sec4_sg(desc, jrdev, state, ctx->ctx_len,
++ ret = ctx_map_to_sec4_sg(jrdev, state, ctx->ctx_len,
+ edesc->sec4_sg, DMA_BIDIRECTIONAL);
+ if (ret)
+ goto unmap_ctx;
+@@ -871,9 +833,8 @@ static int ahash_final_ctx(struct ahash_
+ desc = edesc->hw_desc;
+
+ edesc->sec4_sg_bytes = sec4_sg_bytes;
+- edesc->src_nents = 0;
+
+- ret = ctx_map_to_sec4_sg(desc, jrdev, state, ctx->ctx_len,
++ ret = ctx_map_to_sec4_sg(jrdev, state, ctx->ctx_len,
+ edesc->sec4_sg, DMA_TO_DEVICE);
+ if (ret)
+ goto unmap_ctx;
+@@ -967,7 +928,7 @@ static int ahash_finup_ctx(struct ahash_
+
+ edesc->src_nents = src_nents;
+
+- ret = ctx_map_to_sec4_sg(desc, jrdev, state, ctx->ctx_len,
++ ret = ctx_map_to_sec4_sg(jrdev, state, ctx->ctx_len,
+ edesc->sec4_sg, DMA_TO_DEVICE);
+ if (ret)
+ goto unmap_ctx;
+@@ -1123,7 +1084,6 @@ static int ahash_final_no_ctx(struct aha
+ dev_err(jrdev, "unable to map dst\n");
+ goto unmap;
+ }
+- edesc->src_nents = 0;
+
+ #ifdef DEBUG
+ print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ",
+@@ -1205,7 +1165,6 @@ static int ahash_update_no_ctx(struct ah
+
+ edesc->src_nents = src_nents;
+ edesc->sec4_sg_bytes = sec4_sg_bytes;
+- edesc->dst_dma = 0;
+
+ ret = buf_map_to_sec4_sg(jrdev, edesc->sec4_sg, state);
+ if (ret)
+@@ -1417,7 +1376,6 @@ static int ahash_update_first(struct aha
+ }
+
+ edesc->src_nents = src_nents;
+- edesc->dst_dma = 0;
+
+ ret = ahash_edesc_add_src(ctx, edesc, req, mapped_nents, 0, 0,
+ to_hash);
+@@ -1719,6 +1677,7 @@ static int caam_hash_cra_init(struct cry
+ HASH_MSG_LEN + 64,
+ HASH_MSG_LEN + SHA512_DIGEST_SIZE };
+ dma_addr_t dma_addr;
++ struct caam_drv_private *priv;
+
+ /*
+ * Get a Job ring from Job Ring driver to ensure in-order
+@@ -1730,10 +1689,13 @@ static int caam_hash_cra_init(struct cry
+ return PTR_ERR(ctx->jrdev);
+ }
+
++ priv = dev_get_drvdata(ctx->jrdev->parent);
++ ctx->dir = priv->era >= 6 ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
++
+ dma_addr = dma_map_single_attrs(ctx->jrdev, ctx->sh_desc_update,
+ offsetof(struct caam_hash_ctx,
+ sh_desc_update_dma),
+- DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
++ ctx->dir, DMA_ATTR_SKIP_CPU_SYNC);
+ if (dma_mapping_error(ctx->jrdev, dma_addr)) {
+ dev_err(ctx->jrdev, "unable to map shared descriptors\n");
+ caam_jr_free(ctx->jrdev);
+@@ -1768,7 +1730,7 @@ static void caam_hash_cra_exit(struct cr
+ dma_unmap_single_attrs(ctx->jrdev, ctx->sh_desc_update_dma,
+ offsetof(struct caam_hash_ctx,
+ sh_desc_update_dma),
+- DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
++ ctx->dir, DMA_ATTR_SKIP_CPU_SYNC);
+ caam_jr_free(ctx->jrdev);
+ }
+
+--- /dev/null
++++ b/drivers/crypto/caam/caamhash_desc.c
+@@ -0,0 +1,108 @@
++/*
++ * Shared descriptors for ahash algorithms
++ *
++ * Copyright 2017 NXP
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * * Neither the names of the above-listed copyright holders nor the
++ * names of any contributors may be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "compat.h"
++#include "desc_constr.h"
++#include "caamhash_desc.h"
++
++/**
++ * cnstr_shdsc_ahash - ahash shared descriptor
++ * @desc: pointer to buffer used for descriptor construction
++ * @adata: pointer to authentication transform definitions.
++ * A split key is required for SEC Era < 6; the size of the split key
++ * is specified in this case.
++ * Valid algorithm values - one of OP_ALG_ALGSEL_{MD5, SHA1, SHA224,
++ * SHA256, SHA384, SHA512}.
++ * @state: algorithm state OP_ALG_AS_{INIT, FINALIZE, INITFINALIZE, UPDATE}
++ * @digestsize: algorithm's digest size
++ * @ctx_len: size of Context Register
++ * @import_ctx: true if previous Context Register needs to be restored
++ * must be true for ahash update and final
++ * must be false for for ahash first and digest
++ * @era: SEC Era
++ */
++void cnstr_shdsc_ahash(u32 * const desc, struct alginfo *adata, u32 state,
++ int digestsize, int ctx_len, bool import_ctx, int era)
++{
++ u32 op = adata->algtype;
++
++ init_sh_desc(desc, HDR_SHARE_SERIAL);
++
++ /* Append key if it has been set; ahash update excluded */
++ if (state != OP_ALG_AS_UPDATE && adata->keylen) {
++ u32 *skip_key_load;
++
++ /* Skip key loading if already shared */
++ skip_key_load = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
++ JUMP_COND_SHRD);
++
++ if (era < 6)
++ append_key_as_imm(desc, adata->key_virt,
++ adata->keylen_pad,
++ adata->keylen, CLASS_2 |
++ KEY_DEST_MDHA_SPLIT | KEY_ENC);
++ else
++ append_proto_dkp(desc, adata);
++
++ set_jump_tgt_here(desc, skip_key_load);
++
++ op |= OP_ALG_AAI_HMAC_PRECOMP;
++ }
++
++ /* If needed, import context from software */
++ if (import_ctx)
++ append_seq_load(desc, ctx_len, LDST_CLASS_2_CCB |
++ LDST_SRCDST_BYTE_CONTEXT);
++
++ /* Class 2 operation */
++ append_operation(desc, op | state | OP_ALG_ENCRYPT);
++
++ /*
++ * Load from buf and/or src and write to req->result or state->context
++ * Calculate remaining bytes to read
++ */
++ append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ);
++ /* Read remaining bytes */
++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_LAST2 |
++ FIFOLD_TYPE_MSG | KEY_VLF);
++ /* Store class2 context bytes */
++ append_seq_store(desc, digestsize, LDST_CLASS_2_CCB |
++ LDST_SRCDST_BYTE_CONTEXT);
++}
++EXPORT_SYMBOL(cnstr_shdsc_ahash);
++
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_DESCRIPTION("FSL CAAM ahash descriptors support");
++MODULE_AUTHOR("NXP Semiconductors");
+--- /dev/null
++++ b/drivers/crypto/caam/caamhash_desc.h
+@@ -0,0 +1,49 @@
++/*
++ * Shared descriptors for ahash algorithms
++ *
++ * Copyright 2017 NXP
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * * Neither the names of the above-listed copyright holders nor the
++ * names of any contributors may be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _CAAMHASH_DESC_H_
++#define _CAAMHASH_DESC_H_
++
++/* length of descriptors text */
++#define DESC_AHASH_BASE (3 * CAAM_CMD_SZ)
++#define DESC_AHASH_UPDATE_LEN (6 * CAAM_CMD_SZ)
++#define DESC_AHASH_UPDATE_FIRST_LEN (DESC_AHASH_BASE + 4 * CAAM_CMD_SZ)
++#define DESC_AHASH_FINAL_LEN (DESC_AHASH_BASE + 5 * CAAM_CMD_SZ)
++#define DESC_AHASH_DIGEST_LEN (DESC_AHASH_BASE + 4 * CAAM_CMD_SZ)
++
++void cnstr_shdsc_ahash(u32 * const desc, struct alginfo *adata, u32 state,
++ int digestsize, int ctx_len, bool import_ctx, int era);
++
++#endif /* _CAAMHASH_DESC_H_ */
+--- a/drivers/crypto/caam/compat.h
++++ b/drivers/crypto/caam/compat.h
+@@ -17,6 +17,7 @@
+ #include <linux/of_platform.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/io.h>
++#include <linux/iommu.h>
+ #include <linux/spinlock.h>
+ #include <linux/rtnetlink.h>
+ #include <linux/in.h>
+@@ -38,6 +39,7 @@
+ #include <crypto/authenc.h>
+ #include <crypto/akcipher.h>
+ #include <crypto/scatterwalk.h>
++#include <crypto/skcipher.h>
+ #include <crypto/internal/skcipher.h>
+ #include <crypto/internal/hash.h>
+ #include <crypto/internal/rsa.h>
+--- a/drivers/crypto/caam/ctrl.c
++++ b/drivers/crypto/caam/ctrl.c
+@@ -27,6 +27,8 @@ EXPORT_SYMBOL(caam_imx);
+ #include "qi.h"
+ #endif
+
++static struct platform_device *caam_dma_dev;
++
+ /*
+ * i.MX targets tend to have clock control subsystems that can
+ * enable/disable clocking to our device.
+@@ -332,6 +334,9 @@ static int caam_remove(struct platform_d
+ debugfs_remove_recursive(ctrlpriv->dfs_root);
+ #endif
+
++ if (caam_dma_dev)
++ platform_device_unregister(caam_dma_dev);
++
+ /* Unmap controller region */
+ iounmap(ctrl);
+
+@@ -433,6 +438,10 @@ static int caam_probe(struct platform_de
+ {.family = "Freescale i.MX"},
+ {},
+ };
++ static struct platform_device_info caam_dma_pdev_info = {
++ .name = "caam-dma",
++ .id = PLATFORM_DEVID_NONE
++ };
+ struct device *dev;
+ struct device_node *nprop, *np;
+ struct caam_ctrl __iomem *ctrl;
+@@ -615,6 +624,8 @@ static int caam_probe(struct platform_de
+ goto iounmap_ctrl;
+ }
+
++ ctrlpriv->era = caam_get_era();
++
+ ret = of_platform_populate(nprop, caam_match, NULL, dev);
+ if (ret) {
+ dev_err(dev, "JR platform devices creation error\n");
+@@ -671,6 +682,16 @@ static int caam_probe(struct platform_de
+ goto caam_remove;
+ }
+
++ caam_dma_pdev_info.parent = dev;
++ caam_dma_pdev_info.dma_mask = dma_get_mask(dev);
++ caam_dma_dev = platform_device_register_full(&caam_dma_pdev_info);
++ if (IS_ERR(caam_dma_dev)) {
++ dev_err(dev, "Unable to create and register caam-dma dev\n");
++ caam_dma_dev = 0;
++ } else {
++ set_dma_ops(&caam_dma_dev->dev, get_dma_ops(dev));
++ }
++
+ cha_vid_ls = rd_reg32(&ctrl->perfmon.cha_id_ls);
+
+ /*
+@@ -746,7 +767,7 @@ static int caam_probe(struct platform_de
+
+ /* Report "alive" for developer to see */
+ dev_info(dev, "device ID = 0x%016llx (Era %d)\n", caam_id,
+- caam_get_era());
++ ctrlpriv->era);
+ dev_info(dev, "job rings = %d, qi = %d, dpaa2 = %s\n",
+ ctrlpriv->total_jobrs, ctrlpriv->qi_present,
+ caam_dpaa2 ? "yes" : "no");
+--- a/drivers/crypto/caam/desc.h
++++ b/drivers/crypto/caam/desc.h
+@@ -42,6 +42,7 @@
+ #define CMD_SEQ_LOAD (0x03 << CMD_SHIFT)
+ #define CMD_FIFO_LOAD (0x04 << CMD_SHIFT)
+ #define CMD_SEQ_FIFO_LOAD (0x05 << CMD_SHIFT)
++#define CMD_MOVEB (0x07 << CMD_SHIFT)
+ #define CMD_STORE (0x0a << CMD_SHIFT)
+ #define CMD_SEQ_STORE (0x0b << CMD_SHIFT)
+ #define CMD_FIFO_STORE (0x0c << CMD_SHIFT)
+@@ -355,6 +356,7 @@
+ #define FIFOLD_TYPE_PK_N (0x08 << FIFOLD_TYPE_SHIFT)
+ #define FIFOLD_TYPE_PK_A (0x0c << FIFOLD_TYPE_SHIFT)
+ #define FIFOLD_TYPE_PK_B (0x0d << FIFOLD_TYPE_SHIFT)
++#define FIFOLD_TYPE_IFIFO (0x0f << FIFOLD_TYPE_SHIFT)
+
+ /* Other types. Need to OR in last/flush bits as desired */
+ #define FIFOLD_TYPE_MSG_MASK (0x38 << FIFOLD_TYPE_SHIFT)
+@@ -408,6 +410,7 @@
+ #define FIFOST_TYPE_MESSAGE_DATA (0x30 << FIFOST_TYPE_SHIFT)
+ #define FIFOST_TYPE_RNGSTORE (0x34 << FIFOST_TYPE_SHIFT)
+ #define FIFOST_TYPE_RNGFIFO (0x35 << FIFOST_TYPE_SHIFT)
++#define FIFOST_TYPE_METADATA (0x3e << FIFOST_TYPE_SHIFT)
+ #define FIFOST_TYPE_SKIP (0x3f << FIFOST_TYPE_SHIFT)
+
+ /*
+@@ -444,6 +447,18 @@
+ #define OP_PCLID_DSAVERIFY (0x16 << OP_PCLID_SHIFT)
+ #define OP_PCLID_RSAENC_PUBKEY (0x18 << OP_PCLID_SHIFT)
+ #define OP_PCLID_RSADEC_PRVKEY (0x19 << OP_PCLID_SHIFT)
++#define OP_PCLID_DKP_MD5 (0x20 << OP_PCLID_SHIFT)
++#define OP_PCLID_DKP_SHA1 (0x21 << OP_PCLID_SHIFT)
++#define OP_PCLID_DKP_SHA224 (0x22 << OP_PCLID_SHIFT)
++#define OP_PCLID_DKP_SHA256 (0x23 << OP_PCLID_SHIFT)
++#define OP_PCLID_DKP_SHA384 (0x24 << OP_PCLID_SHIFT)
++#define OP_PCLID_DKP_SHA512 (0x25 << OP_PCLID_SHIFT)
++#define OP_PCLID_DKP_RIF_MD5 (0x60 << OP_PCLID_SHIFT)
++#define OP_PCLID_DKP_RIF_SHA1 (0x61 << OP_PCLID_SHIFT)
++#define OP_PCLID_DKP_RIF_SHA224 (0x62 << OP_PCLID_SHIFT)
++#define OP_PCLID_DKP_RIF_SHA256 (0x63 << OP_PCLID_SHIFT)
++#define OP_PCLID_DKP_RIF_SHA384 (0x64 << OP_PCLID_SHIFT)
++#define OP_PCLID_DKP_RIF_SHA512 (0x65 << OP_PCLID_SHIFT)
+
+ /* Assuming OP_TYPE = OP_TYPE_DECAP_PROTOCOL/ENCAP_PROTOCOL */
+ #define OP_PCLID_IPSEC (0x01 << OP_PCLID_SHIFT)
+@@ -1093,6 +1108,22 @@
+ /* MacSec protinfos */
+ #define OP_PCL_MACSEC 0x0001
+
++/* Derived Key Protocol (DKP) Protinfo */
++#define OP_PCL_DKP_SRC_SHIFT 14
++#define OP_PCL_DKP_SRC_MASK (3 << OP_PCL_DKP_SRC_SHIFT)
++#define OP_PCL_DKP_SRC_IMM (0 << OP_PCL_DKP_SRC_SHIFT)
++#define OP_PCL_DKP_SRC_SEQ (1 << OP_PCL_DKP_SRC_SHIFT)
++#define OP_PCL_DKP_SRC_PTR (2 << OP_PCL_DKP_SRC_SHIFT)
++#define OP_PCL_DKP_SRC_SGF (3 << OP_PCL_DKP_SRC_SHIFT)
++#define OP_PCL_DKP_DST_SHIFT 12
++#define OP_PCL_DKP_DST_MASK (3 << OP_PCL_DKP_DST_SHIFT)
++#define OP_PCL_DKP_DST_IMM (0 << OP_PCL_DKP_DST_SHIFT)
++#define OP_PCL_DKP_DST_SEQ (1 << OP_PCL_DKP_DST_SHIFT)
++#define OP_PCL_DKP_DST_PTR (2 << OP_PCL_DKP_DST_SHIFT)
++#define OP_PCL_DKP_DST_SGF (3 << OP_PCL_DKP_DST_SHIFT)
++#define OP_PCL_DKP_KEY_SHIFT 0
++#define OP_PCL_DKP_KEY_MASK (0xfff << OP_PCL_DKP_KEY_SHIFT)
++
+ /* PKI unidirectional protocol protinfo bits */
+ #define OP_PCL_PKPROT_TEST 0x0008
+ #define OP_PCL_PKPROT_DECRYPT 0x0004
+@@ -1440,10 +1471,11 @@
+ #define MATH_SRC1_REG2 (0x02 << MATH_SRC1_SHIFT)
+ #define MATH_SRC1_REG3 (0x03 << MATH_SRC1_SHIFT)
+ #define MATH_SRC1_IMM (0x04 << MATH_SRC1_SHIFT)
+-#define MATH_SRC1_DPOVRD (0x07 << MATH_SRC0_SHIFT)
++#define MATH_SRC1_DPOVRD (0x07 << MATH_SRC1_SHIFT)
+ #define MATH_SRC1_INFIFO (0x0a << MATH_SRC1_SHIFT)
+ #define MATH_SRC1_OUTFIFO (0x0b << MATH_SRC1_SHIFT)
+ #define MATH_SRC1_ONE (0x0c << MATH_SRC1_SHIFT)
++#define MATH_SRC1_ZERO (0x0f << MATH_SRC1_SHIFT)
+
+ /* Destination selectors */
+ #define MATH_DEST_SHIFT 8
+@@ -1452,6 +1484,7 @@
+ #define MATH_DEST_REG1 (0x01 << MATH_DEST_SHIFT)
+ #define MATH_DEST_REG2 (0x02 << MATH_DEST_SHIFT)
+ #define MATH_DEST_REG3 (0x03 << MATH_DEST_SHIFT)
++#define MATH_DEST_DPOVRD (0x07 << MATH_DEST_SHIFT)
+ #define MATH_DEST_SEQINLEN (0x08 << MATH_DEST_SHIFT)
+ #define MATH_DEST_SEQOUTLEN (0x09 << MATH_DEST_SHIFT)
+ #define MATH_DEST_VARSEQINLEN (0x0a << MATH_DEST_SHIFT)
+@@ -1624,4 +1657,31 @@
+ /* Frame Descriptor Command for Replacement Job Descriptor */
+ #define FD_CMD_REPLACE_JOB_DESC 0x20000000
+
++/* CHA Control Register bits */
++#define CCTRL_RESET_CHA_ALL 0x1
++#define CCTRL_RESET_CHA_AESA 0x2
++#define CCTRL_RESET_CHA_DESA 0x4
++#define CCTRL_RESET_CHA_AFHA 0x8
++#define CCTRL_RESET_CHA_KFHA 0x10
++#define CCTRL_RESET_CHA_SF8A 0x20
++#define CCTRL_RESET_CHA_PKHA 0x40
++#define CCTRL_RESET_CHA_MDHA 0x80
++#define CCTRL_RESET_CHA_CRCA 0x100
++#define CCTRL_RESET_CHA_RNG 0x200
++#define CCTRL_RESET_CHA_SF9A 0x400
++#define CCTRL_RESET_CHA_ZUCE 0x800
++#define CCTRL_RESET_CHA_ZUCA 0x1000
++#define CCTRL_UNLOAD_PK_A0 0x10000
++#define CCTRL_UNLOAD_PK_A1 0x20000
++#define CCTRL_UNLOAD_PK_A2 0x40000
++#define CCTRL_UNLOAD_PK_A3 0x80000
++#define CCTRL_UNLOAD_PK_B0 0x100000
++#define CCTRL_UNLOAD_PK_B1 0x200000
++#define CCTRL_UNLOAD_PK_B2 0x400000
++#define CCTRL_UNLOAD_PK_B3 0x800000
++#define CCTRL_UNLOAD_PK_N 0x1000000
++#define CCTRL_UNLOAD_PK_A 0x4000000
++#define CCTRL_UNLOAD_PK_B 0x8000000
++#define CCTRL_UNLOAD_SBOX 0x10000000
++
+ #endif /* DESC_H */
+--- a/drivers/crypto/caam/desc_constr.h
++++ b/drivers/crypto/caam/desc_constr.h
+@@ -109,7 +109,7 @@ static inline void init_job_desc_shared(
+ append_ptr(desc, ptr);
+ }
+
+-static inline void append_data(u32 * const desc, void *data, int len)
++static inline void append_data(u32 * const desc, const void *data, int len)
+ {
+ u32 *offset = desc_end(desc);
+
+@@ -172,7 +172,7 @@ static inline void append_cmd_ptr_extlen
+ append_cmd(desc, len);
+ }
+
+-static inline void append_cmd_data(u32 * const desc, void *data, int len,
++static inline void append_cmd_data(u32 * const desc, const void *data, int len,
+ u32 command)
+ {
+ append_cmd(desc, command | IMMEDIATE | len);
+@@ -189,6 +189,7 @@ static inline u32 *append_##cmd(u32 * co
+ }
+ APPEND_CMD_RET(jump, JUMP)
+ APPEND_CMD_RET(move, MOVE)
++APPEND_CMD_RET(moveb, MOVEB)
+
+ static inline void set_jump_tgt_here(u32 * const desc, u32 *jump_cmd)
+ {
+@@ -271,7 +272,7 @@ APPEND_SEQ_PTR_INTLEN(in, IN)
+ APPEND_SEQ_PTR_INTLEN(out, OUT)
+
+ #define APPEND_CMD_PTR_TO_IMM(cmd, op) \
+-static inline void append_##cmd##_as_imm(u32 * const desc, void *data, \
++static inline void append_##cmd##_as_imm(u32 * const desc, const void *data, \
+ unsigned int len, u32 options) \
+ { \
+ PRINT_POS; \
+@@ -312,7 +313,7 @@ APPEND_CMD_PTR_LEN(seq_out_ptr, SEQ_OUT_
+ * from length of immediate data provided, e.g., split keys
+ */
+ #define APPEND_CMD_PTR_TO_IMM2(cmd, op) \
+-static inline void append_##cmd##_as_imm(u32 * const desc, void *data, \
++static inline void append_##cmd##_as_imm(u32 * const desc, const void *data, \
+ unsigned int data_len, \
+ unsigned int len, u32 options) \
+ { \
+@@ -452,7 +453,7 @@ struct alginfo {
+ unsigned int keylen_pad;
+ union {
+ dma_addr_t key_dma;
+- void *key_virt;
++ const void *key_virt;
+ };
+ bool key_inline;
+ };
+@@ -496,4 +497,45 @@ static inline int desc_inline_query(unsi
+ return (rem_bytes >= 0) ? 0 : -1;
+ }
+
++/**
++ * append_proto_dkp - Derived Key Protocol (DKP): key -> split key
++ * @desc: pointer to buffer used for descriptor construction
++ * @adata: pointer to authentication transform definitions.
++ * keylen should be the length of initial key, while keylen_pad
++ * the length of the derived (split) key.
++ * Valid algorithm values - one of OP_ALG_ALGSEL_{MD5, SHA1, SHA224,
++ * SHA256, SHA384, SHA512}.
++ */
++static inline void append_proto_dkp(u32 * const desc, struct alginfo *adata)
++{
++ u32 protid;
++
++ /*
++ * Quick & dirty translation from OP_ALG_ALGSEL_{MD5, SHA*}
++ * to OP_PCLID_DKP_{MD5, SHA*}
++ */
++ protid = (adata->algtype & OP_ALG_ALGSEL_SUBMASK) |
++ (0x20 << OP_ALG_ALGSEL_SHIFT);
++
++ if (adata->key_inline) {
++ int words;
++
++ append_operation(desc, OP_TYPE_UNI_PROTOCOL | protid |
++ OP_PCL_DKP_SRC_IMM | OP_PCL_DKP_DST_IMM |
++ adata->keylen);
++ append_data(desc, adata->key_virt, adata->keylen);
++
++ /* Reserve space in descriptor buffer for the derived key */
++ words = (ALIGN(adata->keylen_pad, CAAM_CMD_SZ) -
++ ALIGN(adata->keylen, CAAM_CMD_SZ)) / CAAM_CMD_SZ;
++ if (words)
++ (*desc) = cpu_to_caam32(caam32_to_cpu(*desc) + words);
++ } else {
++ append_operation(desc, OP_TYPE_UNI_PROTOCOL | protid |
++ OP_PCL_DKP_SRC_PTR | OP_PCL_DKP_DST_PTR |
++ adata->keylen);
++ append_ptr(desc, adata->key_dma);
++ }
++}
++
+ #endif /* DESC_CONSTR_H */
+--- /dev/null
++++ b/drivers/crypto/caam/dpseci.c
+@@ -0,0 +1,865 @@
++/*
++ * Copyright 2013-2016 Freescale Semiconductor Inc.
++ * Copyright 2017 NXP
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * * Neither the names of the above-listed copyright holders nor the
++ * names of any contributors may be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/fsl/mc.h>
++#include "../../../drivers/staging/fsl-mc/include/dpopr.h"
++#include "dpseci.h"
++#include "dpseci_cmd.h"
++
++/**
++ * dpseci_open() - Open a control session for the specified object
++ * @mc_io: Pointer to MC portal's I/O object
++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
++ * @dpseci_id: DPSECI unique ID
++ * @token: Returned token; use in subsequent API calls
++ *
++ * This function can be used to open a control session for an already created
++ * object; an object may have been declared in the DPL or by calling the
++ * dpseci_create() function.
++ * This function returns a unique authentication token, associated with the
++ * specific object ID and the specific MC portal; this token must be used in all
++ * subsequent commands for this specific object.
++ *
++ * Return: '0' on success, error code otherwise
++ */
++int dpseci_open(struct fsl_mc_io *mc_io, u32 cmd_flags, int dpseci_id,
++ u16 *token)
++{
++ struct fsl_mc_command cmd = { 0 };
++ struct dpseci_cmd_open *cmd_params;
++ int err;
++
++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_OPEN,
++ cmd_flags,
++ 0);
++ cmd_params = (struct dpseci_cmd_open *)cmd.params;
++ cmd_params->dpseci_id = cpu_to_le32(dpseci_id);
++ err = mc_send_command(mc_io, &cmd);
++ if (err)
++ return err;
++
++ *token = mc_cmd_hdr_read_token(&cmd);
++
++ return 0;
++}
++
++/**
++ * dpseci_close() - Close the control session of the object
++ * @mc_io: Pointer to MC portal's I/O object
++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPSECI object
++ *
++ * After this function is called, no further operations are allowed on the
++ * object without opening a new control session.
++ *
++ * Return: '0' on success, error code otherwise
++ */
++int dpseci_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token)
++{
++ struct fsl_mc_command cmd = { 0 };
++
++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_CLOSE,
++ cmd_flags,
++ token);
++ return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpseci_create() - Create the DPSECI object
++ * @mc_io: Pointer to MC portal's I/O object
++ * @dprc_token: Parent container token; '0' for default container
++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
++ * @cfg: Configuration structure
++ * @obj_id: returned object id
++ *
++ * Create the DPSECI object, allocate required resources and perform required
++ * initialization.
++ *
++ * The object can be created either by declaring it in the DPL file, or by
++ * calling this function.
++ *
++ * The function accepts an authentication token of a parent container that this
++ * object should be assigned to. The token can be '0' so the object will be
++ * assigned to the default container.
++ * The newly created object can be opened with the returned object id and using
++ * the container's associated tokens and MC portals.
++ *
++ * Return: '0' on success, error code otherwise
++ */
++int dpseci_create(struct fsl_mc_io *mc_io, u16 dprc_token, u32 cmd_flags,
++ const struct dpseci_cfg *cfg, u32 *obj_id)
++{
++ struct fsl_mc_command cmd = { 0 };
++ struct dpseci_cmd_create *cmd_params;
++ int i, err;
++
++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_CREATE,
++ cmd_flags,
++ dprc_token);
++ cmd_params = (struct dpseci_cmd_create *)cmd.params;
++ for (i = 0; i < 8; i++)
++ cmd_params->priorities[i] = cfg->priorities[i];
++ for (i = 0; i < 8; i++)
++ cmd_params->priorities2[i] = cfg->priorities[8 + i];
++ cmd_params->num_tx_queues = cfg->num_tx_queues;
++ cmd_params->num_rx_queues = cfg->num_rx_queues;
++ cmd_params->options = cpu_to_le32(cfg->options);
++ err = mc_send_command(mc_io, &cmd);
++ if (err)
++ return err;
++
++ *obj_id = mc_cmd_read_object_id(&cmd);
++
++ return 0;
++}
++
++/**
++ * dpseci_destroy() - Destroy the DPSECI object and release all its resources
++ * @mc_io: Pointer to MC portal's I/O object
++ * @dprc_token: Parent container token; '0' for default container
++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
++ * @object_id: The object id; it must be a valid id within the container that
++ * created this object
++ *
++ * The function accepts the authentication token of the parent container that
++ * created the object (not the one that currently owns the object). The object
++ * is searched within parent using the provided 'object_id'.
++ * All tokens to the object must be closed before calling destroy.
++ *
++ * Return: '0' on success, error code otherwise
++ */
++int dpseci_destroy(struct fsl_mc_io *mc_io, u16 dprc_token, u32 cmd_flags,
++ u32 object_id)
++{
++ struct fsl_mc_command cmd = { 0 };
++ struct dpseci_cmd_destroy *cmd_params;
++
++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_DESTROY,
++ cmd_flags,
++ dprc_token);
++ cmd_params = (struct dpseci_cmd_destroy *)cmd.params;
++ cmd_params->object_id = cpu_to_le32(object_id);
++
++ return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpseci_enable() - Enable the DPSECI, allow sending and receiving frames
++ * @mc_io: Pointer to MC portal's I/O object
++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPSECI object
++ *
++ * Return: '0' on success, error code otherwise
++ */
++int dpseci_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token)
++{
++ struct fsl_mc_command cmd = { 0 };
++
++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_ENABLE,
++ cmd_flags,
++ token);
++ return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpseci_disable() - Disable the DPSECI, stop sending and receiving frames
++ * @mc_io: Pointer to MC portal's I/O object
++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPSECI object
++ *
++ * Return: '0' on success, error code otherwise
++ */
++int dpseci_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token)
++{
++ struct fsl_mc_command cmd = { 0 };
++
++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_DISABLE,
++ cmd_flags,
++ token);
++
++ return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpseci_is_enabled() - Check if the DPSECI is enabled.
++ * @mc_io: Pointer to MC portal's I/O object
++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPSECI object
++ * @en: Returns '1' if object is enabled; '0' otherwise
++ *
++ * Return: '0' on success, error code otherwise
++ */
++int dpseci_is_enabled(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++ int *en)
++{
++ struct fsl_mc_command cmd = { 0 };
++ struct dpseci_rsp_is_enabled *rsp_params;
++ int err;
++
++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_IS_ENABLED,
++ cmd_flags,
++ token);
++ err = mc_send_command(mc_io, &cmd);
++ if (err)
++ return err;
++
++ rsp_params = (struct dpseci_rsp_is_enabled *)cmd.params;
++ *en = dpseci_get_field(rsp_params->is_enabled, ENABLE);
++
++ return 0;
++}
++
++/**
++ * dpseci_reset() - Reset the DPSECI, returns the object to initial state.
++ * @mc_io: Pointer to MC portal's I/O object
++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPSECI object
++ *
++ * Return: '0' on success, error code otherwise
++ */
++int dpseci_reset(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token)
++{
++ struct fsl_mc_command cmd = { 0 };
++
++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_RESET,
++ cmd_flags,
++ token);
++
++ return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpseci_get_irq_enable() - Get overall interrupt state
++ * @mc_io: Pointer to MC portal's I/O object
++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPSECI object
++ * @irq_index: The interrupt index to configure
++ * @en: Returned Interrupt state - enable = 1, disable = 0
++ *
++ * Return: '0' on success, error code otherwise
++ */
++int dpseci_get_irq_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++ u8 irq_index, u8 *en)
++{
++ struct fsl_mc_command cmd = { 0 };
++ struct dpseci_cmd_irq_enable *cmd_params;
++ struct dpseci_rsp_get_irq_enable *rsp_params;
++ int err;
++
++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_IRQ_ENABLE,
++ cmd_flags,
++ token);
++ cmd_params = (struct dpseci_cmd_irq_enable *)cmd.params;
++ cmd_params->irq_index = irq_index;
++ err = mc_send_command(mc_io, &cmd);
++ if (err)
++ return err;
++
++ rsp_params = (struct dpseci_rsp_get_irq_enable *)cmd.params;
++ *en = rsp_params->enable_state;
++
++ return 0;
++}
++
++/**
++ * dpseci_set_irq_enable() - Set overall interrupt state.
++ * @mc_io: Pointer to MC portal's I/O object
++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPSECI object
++ * @irq_index: The interrupt index to configure
++ * @en: Interrupt state - enable = 1, disable = 0
++ *
++ * Allows GPP software to control when interrupts are generated.
++ * Each interrupt can have up to 32 causes. The enable/disable control's the
++ * overall interrupt state. If the interrupt is disabled no causes will cause
++ * an interrupt.
++ *
++ * Return: '0' on success, error code otherwise
++ */
++int dpseci_set_irq_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++ u8 irq_index, u8 en)
++{
++ struct fsl_mc_command cmd = { 0 };
++ struct dpseci_cmd_irq_enable *cmd_params;
++
++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_SET_IRQ_ENABLE,
++ cmd_flags,
++ token);
++ cmd_params = (struct dpseci_cmd_irq_enable *)cmd.params;
++ cmd_params->irq_index = irq_index;
++ cmd_params->enable_state = en;
++
++ return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpseci_get_irq_mask() - Get interrupt mask.
++ * @mc_io: Pointer to MC portal's I/O object
++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPSECI object
++ * @irq_index: The interrupt index to configure
++ * @mask: Returned event mask to trigger interrupt
++ *
++ * Every interrupt can have up to 32 causes and the interrupt model supports
++ * masking/unmasking each cause independently.
++ *
++ * Return: '0' on success, error code otherwise
++ */
++int dpseci_get_irq_mask(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++ u8 irq_index, u32 *mask)
++{
++ struct fsl_mc_command cmd = { 0 };
++ struct dpseci_cmd_irq_mask *cmd_params;
++ int err;
++
++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_IRQ_MASK,
++ cmd_flags,
++ token);
++ cmd_params = (struct dpseci_cmd_irq_mask *)cmd.params;
++ cmd_params->irq_index = irq_index;
++ err = mc_send_command(mc_io, &cmd);
++ if (err)
++ return err;
++
++ *mask = le32_to_cpu(cmd_params->mask);
++
++ return 0;
++}
++
++/**
++ * dpseci_set_irq_mask() - Set interrupt mask.
++ * @mc_io: Pointer to MC portal's I/O object
++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPSECI object
++ * @irq_index: The interrupt index to configure
++ * @mask: event mask to trigger interrupt;
++ * each bit:
++ * 0 = ignore event
++ * 1 = consider event for asserting IRQ
++ *
++ * Every interrupt can have up to 32 causes and the interrupt model supports
++ * masking/unmasking each cause independently
++ *
++ * Return: '0' on success, error code otherwise
++ */
++int dpseci_set_irq_mask(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++ u8 irq_index, u32 mask)
++{
++ struct fsl_mc_command cmd = { 0 };
++ struct dpseci_cmd_irq_mask *cmd_params;
++
++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_SET_IRQ_MASK,
++ cmd_flags,
++ token);
++ cmd_params = (struct dpseci_cmd_irq_mask *)cmd.params;
++ cmd_params->mask = cpu_to_le32(mask);
++ cmd_params->irq_index = irq_index;
++
++ return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpseci_get_irq_status() - Get the current status of any pending interrupts
++ * @mc_io: Pointer to MC portal's I/O object
++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPSECI object
++ * @irq_index: The interrupt index to configure
++ * @status: Returned interrupts status - one bit per cause:
++ * 0 = no interrupt pending
++ * 1 = interrupt pending
++ *
++ * Return: '0' on success, error code otherwise
++ */
++int dpseci_get_irq_status(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++ u8 irq_index, u32 *status)
++{
++ struct fsl_mc_command cmd = { 0 };
++ struct dpseci_cmd_irq_status *cmd_params;
++ int err;
++
++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_IRQ_STATUS,
++ cmd_flags,
++ token);
++ cmd_params = (struct dpseci_cmd_irq_status *)cmd.params;
++ cmd_params->status = cpu_to_le32(*status);
++ cmd_params->irq_index = irq_index;
++ err = mc_send_command(mc_io, &cmd);
++ if (err)
++ return err;
++
++ *status = le32_to_cpu(cmd_params->status);
++
++ return 0;
++}
++
++/**
++ * dpseci_clear_irq_status() - Clear a pending interrupt's status
++ * @mc_io: Pointer to MC portal's I/O object
++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPSECI object
++ * @irq_index: The interrupt index to configure
++ * @status: bits to clear (W1C) - one bit per cause:
++ * 0 = don't change
++ * 1 = clear status bit
++ *
++ * Return: '0' on success, error code otherwise
++ */
++int dpseci_clear_irq_status(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++ u8 irq_index, u32 status)
++{
++ struct fsl_mc_command cmd = { 0 };
++ struct dpseci_cmd_irq_status *cmd_params;
++
++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_CLEAR_IRQ_STATUS,
++ cmd_flags,
++ token);
++ cmd_params = (struct dpseci_cmd_irq_status *)cmd.params;
++ cmd_params->status = cpu_to_le32(status);
++ cmd_params->irq_index = irq_index;
++
++ return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpseci_get_attributes() - Retrieve DPSECI attributes
++ * @mc_io: Pointer to MC portal's I/O object
++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPSECI object
++ * @attr: Returned object's attributes
++ *
++ * Return: '0' on success, error code otherwise
++ */
++int dpseci_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++ struct dpseci_attr *attr)
++{
++ struct fsl_mc_command cmd = { 0 };
++ struct dpseci_rsp_get_attributes *rsp_params;
++ int err;
++
++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_ATTR,
++ cmd_flags,
++ token);
++ err = mc_send_command(mc_io, &cmd);
++ if (err)
++ return err;
++
++ rsp_params = (struct dpseci_rsp_get_attributes *)cmd.params;
++ attr->id = le32_to_cpu(rsp_params->id);
++ attr->num_tx_queues = rsp_params->num_tx_queues;
++ attr->num_rx_queues = rsp_params->num_rx_queues;
++ attr->options = le32_to_cpu(rsp_params->options);
++
++ return 0;
++}
++
++/**
++ * dpseci_set_rx_queue() - Set Rx queue configuration
++ * @mc_io: Pointer to MC portal's I/O object
++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPSECI object
++ * @queue: Select the queue relative to number of priorities configured at
++ * DPSECI creation; use DPSECI_ALL_QUEUES to configure all
++ * Rx queues identically.
++ * @cfg: Rx queue configuration
++ *
++ * Return: '0' on success, error code otherwise
++ */
++int dpseci_set_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++ u8 queue, const struct dpseci_rx_queue_cfg *cfg)
++{
++ struct fsl_mc_command cmd = { 0 };
++ struct dpseci_cmd_queue *cmd_params;
++
++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_SET_RX_QUEUE,
++ cmd_flags,
++ token);
++ cmd_params = (struct dpseci_cmd_queue *)cmd.params;
++ cmd_params->dest_id = cpu_to_le32(cfg->dest_cfg.dest_id);
++ cmd_params->priority = cfg->dest_cfg.priority;
++ cmd_params->queue = queue;
++ dpseci_set_field(cmd_params->dest_type, DEST_TYPE,
++ cfg->dest_cfg.dest_type);
++ cmd_params->user_ctx = cpu_to_le64(cfg->user_ctx);
++ cmd_params->options = cpu_to_le32(cfg->options);
++ dpseci_set_field(cmd_params->order_preservation_en, ORDER_PRESERVATION,
++ cfg->order_preservation_en);
++
++ return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpseci_get_rx_queue() - Retrieve Rx queue attributes
++ * @mc_io: Pointer to MC portal's I/O object
++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPSECI object
++ * @queue: Select the queue relative to number of priorities configured at
++ * DPSECI creation
++ * @attr: Returned Rx queue attributes
++ *
++ * Return: '0' on success, error code otherwise
++ */
++int dpseci_get_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++ u8 queue, struct dpseci_rx_queue_attr *attr)
++{
++ struct fsl_mc_command cmd = { 0 };
++ struct dpseci_cmd_queue *cmd_params;
++ int err;
++
++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_RX_QUEUE,
++ cmd_flags,
++ token);
++ cmd_params = (struct dpseci_cmd_queue *)cmd.params;
++ cmd_params->queue = queue;
++ err = mc_send_command(mc_io, &cmd);
++ if (err)
++ return err;
++
++ attr->dest_cfg.dest_id = le32_to_cpu(cmd_params->dest_id);
++ attr->dest_cfg.priority = cmd_params->priority;
++ attr->dest_cfg.dest_type = dpseci_get_field(cmd_params->dest_type,
++ DEST_TYPE);
++ attr->user_ctx = le64_to_cpu(cmd_params->user_ctx);
++ attr->fqid = le32_to_cpu(cmd_params->fqid);
++ attr->order_preservation_en =
++ dpseci_get_field(cmd_params->order_preservation_en,
++ ORDER_PRESERVATION);
++
++ return 0;
++}
++
++/**
++ * dpseci_get_tx_queue() - Retrieve Tx queue attributes
++ * @mc_io: Pointer to MC portal's I/O object
++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPSECI object
++ * @queue: Select the queue relative to number of priorities configured at
++ * DPSECI creation
++ * @attr: Returned Tx queue attributes
++ *
++ * Return: '0' on success, error code otherwise
++ */
++int dpseci_get_tx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++ u8 queue, struct dpseci_tx_queue_attr *attr)
++{
++ struct fsl_mc_command cmd = { 0 };
++ struct dpseci_cmd_queue *cmd_params;
++ struct dpseci_rsp_get_tx_queue *rsp_params;
++ int err;
++
++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_TX_QUEUE,
++ cmd_flags,
++ token);
++ cmd_params = (struct dpseci_cmd_queue *)cmd.params;
++ cmd_params->queue = queue;
++ err = mc_send_command(mc_io, &cmd);
++ if (err)
++ return err;
++
++ rsp_params = (struct dpseci_rsp_get_tx_queue *)cmd.params;
++ attr->fqid = le32_to_cpu(rsp_params->fqid);
++ attr->priority = rsp_params->priority;
++
++ return 0;
++}
++
++/**
++ * dpseci_get_sec_attr() - Retrieve SEC accelerator attributes
++ * @mc_io: Pointer to MC portal's I/O object
++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPSECI object
++ * @attr: Returned SEC attributes
++ *
++ * Return: '0' on success, error code otherwise
++ */
++int dpseci_get_sec_attr(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++ struct dpseci_sec_attr *attr)
++{
++ struct fsl_mc_command cmd = { 0 };
++ struct dpseci_rsp_get_sec_attr *rsp_params;
++ int err;
++
++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_SEC_ATTR,
++ cmd_flags,
++ token);
++ err = mc_send_command(mc_io, &cmd);
++ if (err)
++ return err;
++
++ rsp_params = (struct dpseci_rsp_get_sec_attr *)cmd.params;
++ attr->ip_id = le16_to_cpu(rsp_params->ip_id);
++ attr->major_rev = rsp_params->major_rev;
++ attr->minor_rev = rsp_params->minor_rev;
++ attr->era = rsp_params->era;
++ attr->deco_num = rsp_params->deco_num;
++ attr->zuc_auth_acc_num = rsp_params->zuc_auth_acc_num;
++ attr->zuc_enc_acc_num = rsp_params->zuc_enc_acc_num;
++ attr->snow_f8_acc_num = rsp_params->snow_f8_acc_num;
++ attr->snow_f9_acc_num = rsp_params->snow_f9_acc_num;
++ attr->crc_acc_num = rsp_params->crc_acc_num;
++ attr->pk_acc_num = rsp_params->pk_acc_num;
++ attr->kasumi_acc_num = rsp_params->kasumi_acc_num;
++ attr->rng_acc_num = rsp_params->rng_acc_num;
++ attr->md_acc_num = rsp_params->md_acc_num;
++ attr->arc4_acc_num = rsp_params->arc4_acc_num;
++ attr->des_acc_num = rsp_params->des_acc_num;
++ attr->aes_acc_num = rsp_params->aes_acc_num;
++ attr->ccha_acc_num = rsp_params->ccha_acc_num;
++ attr->ptha_acc_num = rsp_params->ptha_acc_num;
++
++ return 0;
++}
++
++/**
++ * dpseci_get_sec_counters() - Retrieve SEC accelerator counters
++ * @mc_io: Pointer to MC portal's I/O object
++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPSECI object
++ * @counters: Returned SEC counters
++ *
++ * Return: '0' on success, error code otherwise
++ */
++int dpseci_get_sec_counters(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++ struct dpseci_sec_counters *counters)
++{
++ struct fsl_mc_command cmd = { 0 };
++ struct dpseci_rsp_get_sec_counters *rsp_params;
++ int err;
++
++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_SEC_COUNTERS,
++ cmd_flags,
++ token);
++ err = mc_send_command(mc_io, &cmd);
++ if (err)
++ return err;
++
++ rsp_params = (struct dpseci_rsp_get_sec_counters *)cmd.params;
++ counters->dequeued_requests =
++ le64_to_cpu(rsp_params->dequeued_requests);
++ counters->ob_enc_requests = le64_to_cpu(rsp_params->ob_enc_requests);
++ counters->ib_dec_requests = le64_to_cpu(rsp_params->ib_dec_requests);
++ counters->ob_enc_bytes = le64_to_cpu(rsp_params->ob_enc_bytes);
++ counters->ob_prot_bytes = le64_to_cpu(rsp_params->ob_prot_bytes);
++ counters->ib_dec_bytes = le64_to_cpu(rsp_params->ib_dec_bytes);
++ counters->ib_valid_bytes = le64_to_cpu(rsp_params->ib_valid_bytes);
++
++ return 0;
++}
++
++/**
++ * dpseci_get_api_version() - Get Data Path SEC Interface API version
++ * @mc_io: Pointer to MC portal's I/O object
++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
++ * @major_ver: Major version of data path sec API
++ * @minor_ver: Minor version of data path sec API
++ *
++ * Return: '0' on success, error code otherwise
++ */
++int dpseci_get_api_version(struct fsl_mc_io *mc_io, u32 cmd_flags,
++ u16 *major_ver, u16 *minor_ver)
++{
++ struct fsl_mc_command cmd = { 0 };
++ struct dpseci_rsp_get_api_version *rsp_params;
++ int err;
++
++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_API_VERSION,
++ cmd_flags, 0);
++ err = mc_send_command(mc_io, &cmd);
++ if (err)
++ return err;
++
++ rsp_params = (struct dpseci_rsp_get_api_version *)cmd.params;
++ *major_ver = le16_to_cpu(rsp_params->major);
++ *minor_ver = le16_to_cpu(rsp_params->minor);
++
++ return 0;
++}
++
++/**
++ * dpseci_set_opr() - Set Order Restoration configuration
++ * @mc_io: Pointer to MC portal's I/O object
++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPSECI object
++ * @index: The queue index
++ * @options: Configuration mode options; can be OPR_OPT_CREATE or
++ * OPR_OPT_RETIRE
++ * @cfg: Configuration options for the OPR
++ *
++ * Return: '0' on success, error code otherwise
++ */
++int dpseci_set_opr(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, u8 index,
++ u8 options, struct opr_cfg *cfg)
++{
++ struct fsl_mc_command cmd = { 0 };
++ struct dpseci_cmd_opr *cmd_params;
++
++ cmd.header = mc_encode_cmd_header(
++ DPSECI_CMDID_SET_OPR,
++ cmd_flags,
++ token);
++ cmd_params = (struct dpseci_cmd_opr *)cmd.params;
++ cmd_params->index = index;
++ cmd_params->options = options;
++ cmd_params->oloe = cfg->oloe;
++ cmd_params->oeane = cfg->oeane;
++ cmd_params->olws = cfg->olws;
++ cmd_params->oa = cfg->oa;
++ cmd_params->oprrws = cfg->oprrws;
++
++ return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpseci_get_opr() - Retrieve Order Restoration config and query
++ * @mc_io: Pointer to MC portal's I/O object
++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPSECI object
++ * @index: The queue index
++ * @cfg: Returned OPR configuration
++ * @qry: Returned OPR query
++ *
++ * Return: '0' on success, error code otherwise
++ */
++int dpseci_get_opr(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, u8 index,
++ struct opr_cfg *cfg, struct opr_qry *qry)
++{
++ struct fsl_mc_command cmd = { 0 };
++ struct dpseci_cmd_opr *cmd_params;
++ struct dpseci_rsp_get_opr *rsp_params;
++ int err;
++
++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_OPR,
++ cmd_flags,
++ token);
++ cmd_params = (struct dpseci_cmd_opr *)cmd.params;
++ cmd_params->index = index;
++ err = mc_send_command(mc_io, &cmd);
++ if (err)
++ return err;
++
++ rsp_params = (struct dpseci_rsp_get_opr *)cmd.params;
++ qry->rip = dpseci_get_field(rsp_params->flags, OPR_RIP);
++ qry->enable = dpseci_get_field(rsp_params->flags, OPR_ENABLE);
++ cfg->oloe = rsp_params->oloe;
++ cfg->oeane = rsp_params->oeane;
++ cfg->olws = rsp_params->olws;
++ cfg->oa = rsp_params->oa;
++ cfg->oprrws = rsp_params->oprrws;
++ qry->nesn = le16_to_cpu(rsp_params->nesn);
++ qry->ndsn = le16_to_cpu(rsp_params->ndsn);
++ qry->ea_tseq = le16_to_cpu(rsp_params->ea_tseq);
++ qry->tseq_nlis = dpseci_get_field(rsp_params->tseq_nlis, OPR_TSEQ_NLIS);
++ qry->ea_hseq = le16_to_cpu(rsp_params->ea_hseq);
++ qry->hseq_nlis = dpseci_get_field(rsp_params->hseq_nlis, OPR_HSEQ_NLIS);
++ qry->ea_hptr = le16_to_cpu(rsp_params->ea_hptr);
++ qry->ea_tptr = le16_to_cpu(rsp_params->ea_tptr);
++ qry->opr_vid = le16_to_cpu(rsp_params->opr_vid);
++ qry->opr_id = le16_to_cpu(rsp_params->opr_id);
++
++ return 0;
++}
++
++/**
++ * dpseci_set_congestion_notification() - Set congestion group
++ * notification configuration
++ * @mc_io: Pointer to MC portal's I/O object
++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPSECI object
++ * @cfg: congestion notification configuration
++ *
++ * Return: '0' on success, error code otherwise
++ */
++int dpseci_set_congestion_notification(struct fsl_mc_io *mc_io, u32 cmd_flags,
++ u16 token, const struct dpseci_congestion_notification_cfg *cfg)
++{
++ struct fsl_mc_command cmd = { 0 };
++ struct dpseci_cmd_congestion_notification *cmd_params;
++
++ cmd.header = mc_encode_cmd_header(
++ DPSECI_CMDID_SET_CONGESTION_NOTIFICATION,
++ cmd_flags,
++ token);
++ cmd_params = (struct dpseci_cmd_congestion_notification *)cmd.params;
++ cmd_params->dest_id = cpu_to_le32(cfg->dest_cfg.dest_id);
++ cmd_params->notification_mode = cpu_to_le16(cfg->notification_mode);
++ cmd_params->priority = cfg->dest_cfg.priority;
++ dpseci_set_field(cmd_params->options, CGN_DEST_TYPE,
++ cfg->dest_cfg.dest_type);
++ dpseci_set_field(cmd_params->options, CGN_UNITS, cfg->units);
++ cmd_params->message_iova = cpu_to_le64(cfg->message_iova);
++ cmd_params->message_ctx = cpu_to_le64(cfg->message_ctx);
++ cmd_params->threshold_entry = cpu_to_le32(cfg->threshold_entry);
++ cmd_params->threshold_exit = cpu_to_le32(cfg->threshold_exit);
++
++ return mc_send_command(mc_io, &cmd);
++}
++
++/**
++ * dpseci_get_congestion_notification() - Get congestion group notification
++ * configuration
++ * @mc_io: Pointer to MC portal's I/O object
++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
++ * @token: Token of DPSECI object
++ * @cfg: congestion notification configuration
++ *
++ * Return: '0' on success, error code otherwise
++ */
++int dpseci_get_congestion_notification(struct fsl_mc_io *mc_io, u32 cmd_flags,
++ u16 token, struct dpseci_congestion_notification_cfg *cfg)
++{
++ struct fsl_mc_command cmd = { 0 };
++ struct dpseci_cmd_congestion_notification *rsp_params;
++ int err;
++
++ cmd.header = mc_encode_cmd_header(
++ DPSECI_CMDID_GET_CONGESTION_NOTIFICATION,
++ cmd_flags,
++ token);
++ err = mc_send_command(mc_io, &cmd);
++ if (err)
++ return err;
++
++ rsp_params = (struct dpseci_cmd_congestion_notification *)cmd.params;
++ cfg->dest_cfg.dest_id = le32_to_cpu(rsp_params->dest_id);
++ cfg->notification_mode = le16_to_cpu(rsp_params->notification_mode);
++ cfg->dest_cfg.priority = rsp_params->priority;
++ cfg->dest_cfg.dest_type = dpseci_get_field(rsp_params->options,
++ CGN_DEST_TYPE);
++ cfg->units = dpseci_get_field(rsp_params->options, CGN_UNITS);
++ cfg->message_iova = le64_to_cpu(rsp_params->message_iova);
++ cfg->message_ctx = le64_to_cpu(rsp_params->message_ctx);
++ cfg->threshold_entry = le32_to_cpu(rsp_params->threshold_entry);
++ cfg->threshold_exit = le32_to_cpu(rsp_params->threshold_exit);
++
++ return 0;
++}
+--- /dev/null
++++ b/drivers/crypto/caam/dpseci.h
+@@ -0,0 +1,433 @@
++/*
++ * Copyright 2013-2016 Freescale Semiconductor Inc.
++ * Copyright 2017 NXP
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * * Neither the names of the above-listed copyright holders nor the
++ * names of any contributors may be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ */
++#ifndef _DPSECI_H_
++#define _DPSECI_H_
++
++/*
++ * Data Path SEC Interface API
++ * Contains initialization APIs and runtime control APIs for DPSECI
++ */
++
++struct fsl_mc_io;
++struct opr_cfg;
++struct opr_qry;
++
++/**
++ * General DPSECI macros
++ */
++
++/**
++ * Maximum number of Tx/Rx queues per DPSECI object
++ */
++#define DPSECI_MAX_QUEUE_NUM 16
++
++/**
++ * All queues considered; see dpseci_set_rx_queue()
++ */
++#define DPSECI_ALL_QUEUES (u8)(-1)
++
++int dpseci_open(struct fsl_mc_io *mc_io, u32 cmd_flags, int dpseci_id,
++ u16 *token);
++
++int dpseci_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token);
++
++/**
++ * Enable the Congestion Group support
++ */
++#define DPSECI_OPT_HAS_CG 0x000020
++
++/**
++ * Enable the Order Restoration support
++ */
++#define DPSECI_OPT_HAS_OPR 0x000040
++
++/**
++ * Order Point Records are shared for the entire DPSECI
++ */
++#define DPSECI_OPT_OPR_SHARED 0x000080
++
++/**
++ * struct dpseci_cfg - Structure representing DPSECI configuration
++ * @options: Any combination of the following options:
++ * DPSECI_OPT_HAS_CG
++ * DPSECI_OPT_HAS_OPR
++ * DPSECI_OPT_OPR_SHARED
++ * @num_tx_queues: num of queues towards the SEC
++ * @num_rx_queues: num of queues back from the SEC
++ * @priorities: Priorities for the SEC hardware processing;
++ * each place in the array is the priority of the tx queue
++ * towards the SEC;
++ * valid priorities are configured with values 1-8;
++ */
++struct dpseci_cfg {
++ u32 options;
++ u8 num_tx_queues;
++ u8 num_rx_queues;
++ u8 priorities[DPSECI_MAX_QUEUE_NUM];
++};
++
++int dpseci_create(struct fsl_mc_io *mc_io, u16 dprc_token, u32 cmd_flags,
++ const struct dpseci_cfg *cfg, u32 *obj_id);
++
++int dpseci_destroy(struct fsl_mc_io *mc_io, u16 dprc_token, u32 cmd_flags,
++ u32 object_id);
++
++int dpseci_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token);
++
++int dpseci_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token);
++
++int dpseci_is_enabled(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++ int *en);
++
++int dpseci_reset(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token);
++
++int dpseci_get_irq_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++ u8 irq_index, u8 *en);
++
++int dpseci_set_irq_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++ u8 irq_index, u8 en);
++
++int dpseci_get_irq_mask(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++ u8 irq_index, u32 *mask);
++
++int dpseci_set_irq_mask(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++ u8 irq_index, u32 mask);
++
++int dpseci_get_irq_status(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++ u8 irq_index, u32 *status);
++
++int dpseci_clear_irq_status(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++ u8 irq_index, u32 status);
++
++/**
++ * struct dpseci_attr - Structure representing DPSECI attributes
++ * @id: DPSECI object ID
++ * @num_tx_queues: number of queues towards the SEC
++ * @num_rx_queues: number of queues back from the SEC
++ * @options: any combination of the following options:
++ * DPSECI_OPT_HAS_CG
++ * DPSECI_OPT_HAS_OPR
++ * DPSECI_OPT_OPR_SHARED
++ */
++struct dpseci_attr {
++ int id;
++ u8 num_tx_queues;
++ u8 num_rx_queues;
++ u32 options;
++};
++
++int dpseci_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++ struct dpseci_attr *attr);
++
++/**
++ * enum dpseci_dest - DPSECI destination types
++ * @DPSECI_DEST_NONE: Unassigned destination; The queue is set in parked mode
++ * and does not generate FQDAN notifications; user is expected to dequeue
++ * from the queue based on polling or other user-defined method
++ * @DPSECI_DEST_DPIO: The queue is set in schedule mode and generates FQDAN
++ * notifications to the specified DPIO; user is expected to dequeue from
++ * the queue only after notification is received
++ * @DPSECI_DEST_DPCON: The queue is set in schedule mode and does not generate
++ * FQDAN notifications, but is connected to the specified DPCON object;
++ * user is expected to dequeue from the DPCON channel
++ */
++enum dpseci_dest {
++ DPSECI_DEST_NONE = 0,
++ DPSECI_DEST_DPIO,
++ DPSECI_DEST_DPCON
++};
++
++/**
++ * struct dpseci_dest_cfg - Structure representing DPSECI destination parameters
++ * @dest_type: Destination type
++ * @dest_id: Either DPIO ID or DPCON ID, depending on the destination type
++ * @priority: Priority selection within the DPIO or DPCON channel; valid values
++ * are 0-1 or 0-7, depending on the number of priorities in that channel;
++ * not relevant for 'DPSECI_DEST_NONE' option
++ */
++struct dpseci_dest_cfg {
++ enum dpseci_dest dest_type;
++ int dest_id;
++ u8 priority;
++};
++
++/**
++ * DPSECI queue modification options
++ */
++
++/**
++ * Select to modify the user's context associated with the queue
++ */
++#define DPSECI_QUEUE_OPT_USER_CTX 0x00000001
++
++/**
++ * Select to modify the queue's destination
++ */
++#define DPSECI_QUEUE_OPT_DEST 0x00000002
++
++/**
++ * Select to modify the queue's order preservation
++ */
++#define DPSECI_QUEUE_OPT_ORDER_PRESERVATION 0x00000004
++
++/**
++ * struct dpseci_rx_queue_cfg - DPSECI RX queue configuration
++ * @options: Flags representing the suggested modifications to the queue;
++ * Use any combination of 'DPSECI_QUEUE_OPT_<X>' flags
++ * @order_preservation_en: order preservation configuration for the rx queue
++ * valid only if 'DPSECI_QUEUE_OPT_ORDER_PRESERVATION' is contained in 'options'
++ * @user_ctx: User context value provided in the frame descriptor of each
++ * dequeued frame; valid only if 'DPSECI_QUEUE_OPT_USER_CTX' is contained
++ * in 'options'
++ * @dest_cfg: Queue destination parameters; valid only if
++ * 'DPSECI_QUEUE_OPT_DEST' is contained in 'options'
++ */
++struct dpseci_rx_queue_cfg {
++ u32 options;
++ int order_preservation_en;
++ u64 user_ctx;
++ struct dpseci_dest_cfg dest_cfg;
++};
++
++int dpseci_set_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++ u8 queue, const struct dpseci_rx_queue_cfg *cfg);
++
++/**
++ * struct dpseci_rx_queue_attr - Structure representing attributes of Rx queues
++ * @user_ctx: User context value provided in the frame descriptor of each
++ * dequeued frame
++ * @order_preservation_en: Status of the order preservation configuration on the
++ * queue
++ * @dest_cfg: Queue destination configuration
++ * @fqid: Virtual FQID value to be used for dequeue operations
++ */
++struct dpseci_rx_queue_attr {
++ u64 user_ctx;
++ int order_preservation_en;
++ struct dpseci_dest_cfg dest_cfg;
++ u32 fqid;
++};
++
++int dpseci_get_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++ u8 queue, struct dpseci_rx_queue_attr *attr);
++
++/**
++ * struct dpseci_tx_queue_attr - Structure representing attributes of Tx queues
++ * @fqid: Virtual FQID to be used for sending frames to SEC hardware
++ * @priority: SEC hardware processing priority for the queue
++ */
++struct dpseci_tx_queue_attr {
++ u32 fqid;
++ u8 priority;
++};
++
++int dpseci_get_tx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++ u8 queue, struct dpseci_tx_queue_attr *attr);
++
++/**
++ * struct dpseci_sec_attr - Structure representing attributes of the SEC
++ * hardware accelerator
++ * @ip_id: ID for SEC
++ * @major_rev: Major revision number for SEC
++ * @minor_rev: Minor revision number for SEC
++ * @era: SEC Era
++ * @deco_num: The number of copies of the DECO that are implemented in this
++ * version of SEC
++ * @zuc_auth_acc_num: The number of copies of ZUCA that are implemented in this
++ * version of SEC
++ * @zuc_enc_acc_num: The number of copies of ZUCE that are implemented in this
++ * version of SEC
++ * @snow_f8_acc_num: The number of copies of the SNOW-f8 module that are
++ * implemented in this version of SEC
++ * @snow_f9_acc_num: The number of copies of the SNOW-f9 module that are
++ * implemented in this version of SEC
++ * @crc_acc_num: The number of copies of the CRC module that are implemented in
++ * this version of SEC
++ * @pk_acc_num: The number of copies of the Public Key module that are
++ * implemented in this version of SEC
++ * @kasumi_acc_num: The number of copies of the Kasumi module that are
++ * implemented in this version of SEC
++ * @rng_acc_num: The number of copies of the Random Number Generator that are
++ * implemented in this version of SEC
++ * @md_acc_num: The number of copies of the MDHA (Hashing module) that are
++ * implemented in this version of SEC
++ * @arc4_acc_num: The number of copies of the ARC4 module that are implemented
++ * in this version of SEC
++ * @des_acc_num: The number of copies of the DES module that are implemented in
++ * this version of SEC
++ * @aes_acc_num: The number of copies of the AES module that are implemented in
++ * this version of SEC
++ * @ccha_acc_num: The number of copies of the ChaCha20 module that are
++ * implemented in this version of SEC.
++ * @ptha_acc_num: The number of copies of the Poly1305 module that are
++ * implemented in this version of SEC.
++ **/
++struct dpseci_sec_attr {
++ u16 ip_id;
++ u8 major_rev;
++ u8 minor_rev;
++ u8 era;
++ u8 deco_num;
++ u8 zuc_auth_acc_num;
++ u8 zuc_enc_acc_num;
++ u8 snow_f8_acc_num;
++ u8 snow_f9_acc_num;
++ u8 crc_acc_num;
++ u8 pk_acc_num;
++ u8 kasumi_acc_num;
++ u8 rng_acc_num;
++ u8 md_acc_num;
++ u8 arc4_acc_num;
++ u8 des_acc_num;
++ u8 aes_acc_num;
++ u8 ccha_acc_num;
++ u8 ptha_acc_num;
++};
++
++int dpseci_get_sec_attr(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++ struct dpseci_sec_attr *attr);
++
++/**
++ * struct dpseci_sec_counters - Structure representing global SEC counters and
++ * not per dpseci counters
++ * @dequeued_requests: Number of Requests Dequeued
++ * @ob_enc_requests: Number of Outbound Encrypt Requests
++ * @ib_dec_requests: Number of Inbound Decrypt Requests
++ * @ob_enc_bytes: Number of Outbound Bytes Encrypted
++ * @ob_prot_bytes: Number of Outbound Bytes Protected
++ * @ib_dec_bytes: Number of Inbound Bytes Decrypted
++ * @ib_valid_bytes: Number of Inbound Bytes Validated
++ */
++struct dpseci_sec_counters {
++ u64 dequeued_requests;
++ u64 ob_enc_requests;
++ u64 ib_dec_requests;
++ u64 ob_enc_bytes;
++ u64 ob_prot_bytes;
++ u64 ib_dec_bytes;
++ u64 ib_valid_bytes;
++};
++
++int dpseci_get_sec_counters(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
++ struct dpseci_sec_counters *counters);
++
++int dpseci_get_api_version(struct fsl_mc_io *mc_io, u32 cmd_flags,
++ u16 *major_ver, u16 *minor_ver);
++
++int dpseci_set_opr(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, u8 index,
++ u8 options, struct opr_cfg *cfg);
++
++int dpseci_get_opr(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, u8 index,
++ struct opr_cfg *cfg, struct opr_qry *qry);
++
++/**
++ * enum dpseci_congestion_unit - DPSECI congestion units
++ * @DPSECI_CONGESTION_UNIT_BYTES: bytes units
++ * @DPSECI_CONGESTION_UNIT_FRAMES: frames units
++ */
++enum dpseci_congestion_unit {
++ DPSECI_CONGESTION_UNIT_BYTES = 0,
++ DPSECI_CONGESTION_UNIT_FRAMES
++};
++
++/**
++ * CSCN message is written to message_iova once entering a
++ * congestion state (see 'threshold_entry')
++ */
++#define DPSECI_CGN_MODE_WRITE_MEM_ON_ENTER 0x00000001
++
++/**
++ * CSCN message is written to message_iova once exiting a
++ * congestion state (see 'threshold_exit')
++ */
++#define DPSECI_CGN_MODE_WRITE_MEM_ON_EXIT 0x00000002
++
++/**
++ * CSCN write will attempt to allocate into a cache (coherent write);
++ * valid only if 'DPSECI_CGN_MODE_WRITE_MEM_<X>' is selected
++ */
++#define DPSECI_CGN_MODE_COHERENT_WRITE 0x00000004
++
++/**
++ * if 'dpseci_dest_cfg.dest_type != DPSECI_DEST_NONE' CSCN message is sent to
++ * DPIO/DPCON's WQ channel once entering a congestion state
++ * (see 'threshold_entry')
++ */
++#define DPSECI_CGN_MODE_NOTIFY_DEST_ON_ENTER 0x00000008
++
++/**
++ * if 'dpseci_dest_cfg.dest_type != DPSECI_DEST_NONE' CSCN message is sent to
++ * DPIO/DPCON's WQ channel once exiting a congestion state
++ * (see 'threshold_exit')
++ */
++#define DPSECI_CGN_MODE_NOTIFY_DEST_ON_EXIT 0x00000010
++
++/**
++ * if 'dpseci_dest_cfg.dest_type != DPSECI_DEST_NONE' when the CSCN is written
++ * to the sw-portal's DQRR, the DQRI interrupt is asserted immediately
++ * (if enabled)
++ */
++#define DPSECI_CGN_MODE_INTR_COALESCING_DISABLED 0x00000020
++
++/**
++ * struct dpseci_congestion_notification_cfg - congestion notification
++ * configuration
++ * @units: units type
++ * @threshold_entry: above this threshold we enter a congestion state.
++ * set it to '0' to disable it
++ * @threshold_exit: below this threshold we exit the congestion state.
++ * @message_ctx: The context that will be part of the CSCN message
++ * @message_iova: I/O virtual address (must be in DMA-able memory),
++ * must be 16B aligned;
++ * @dest_cfg: CSCN can be send to either DPIO or DPCON WQ channel
++ * @notification_mode: Mask of available options; use 'DPSECI_CGN_MODE_<X>'
++ * values
++ */
++struct dpseci_congestion_notification_cfg {
++ enum dpseci_congestion_unit units;
++ u32 threshold_entry;
++ u32 threshold_exit;
++ u64 message_ctx;
++ u64 message_iova;
++ struct dpseci_dest_cfg dest_cfg;
++ u16 notification_mode;
++};
++
++int dpseci_set_congestion_notification(struct fsl_mc_io *mc_io, u32 cmd_flags,
++ u16 token, const struct dpseci_congestion_notification_cfg *cfg);
++
++int dpseci_get_congestion_notification(struct fsl_mc_io *mc_io, u32 cmd_flags,
++ u16 token, struct dpseci_congestion_notification_cfg *cfg);
++
++#endif /* _DPSECI_H_ */
+--- /dev/null
++++ b/drivers/crypto/caam/dpseci_cmd.h
+@@ -0,0 +1,287 @@
++/*
++ * Copyright 2013-2016 Freescale Semiconductor Inc.
++ * Copyright 2017 NXP
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * * Neither the names of the above-listed copyright holders nor the
++ * names of any contributors may be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _DPSECI_CMD_H_
++#define _DPSECI_CMD_H_
++
++/* DPSECI Version */
++#define DPSECI_VER_MAJOR 5
++#define DPSECI_VER_MINOR 3
++
++#define DPSECI_VER(maj, min) (((maj) << 16) | (min))
++#define DPSECI_VERSION DPSECI_VER(DPSECI_VER_MAJOR, DPSECI_VER_MINOR)
++
++/* Command versioning */
++#define DPSECI_CMD_BASE_VERSION 1
++#define DPSECI_CMD_BASE_VERSION_V2 2
++#define DPSECI_CMD_BASE_VERSION_V3 3
++#define DPSECI_CMD_ID_OFFSET 4
++
++#define DPSECI_CMD_V1(id) (((id) << DPSECI_CMD_ID_OFFSET) | \
++ DPSECI_CMD_BASE_VERSION)
++
++#define DPSECI_CMD_V2(id) (((id) << DPSECI_CMD_ID_OFFSET) | \
++ DPSECI_CMD_BASE_VERSION_V2)
++
++#define DPSECI_CMD_V3(id) (((id) << DPSECI_CMD_ID_OFFSET) | \
++ DPSECI_CMD_BASE_VERSION_V3)
++
++/* Command IDs */
++#define DPSECI_CMDID_CLOSE DPSECI_CMD_V1(0x800)
++#define DPSECI_CMDID_OPEN DPSECI_CMD_V1(0x809)
++#define DPSECI_CMDID_CREATE DPSECI_CMD_V3(0x909)
++#define DPSECI_CMDID_DESTROY DPSECI_CMD_V1(0x989)
++#define DPSECI_CMDID_GET_API_VERSION DPSECI_CMD_V1(0xa09)
++
++#define DPSECI_CMDID_ENABLE DPSECI_CMD_V1(0x002)
++#define DPSECI_CMDID_DISABLE DPSECI_CMD_V1(0x003)
++#define DPSECI_CMDID_GET_ATTR DPSECI_CMD_V1(0x004)
++#define DPSECI_CMDID_RESET DPSECI_CMD_V1(0x005)
++#define DPSECI_CMDID_IS_ENABLED DPSECI_CMD_V1(0x006)
++
++#define DPSECI_CMDID_SET_IRQ_ENABLE DPSECI_CMD_V1(0x012)
++#define DPSECI_CMDID_GET_IRQ_ENABLE DPSECI_CMD_V1(0x013)
++#define DPSECI_CMDID_SET_IRQ_MASK DPSECI_CMD_V1(0x014)
++#define DPSECI_CMDID_GET_IRQ_MASK DPSECI_CMD_V1(0x015)
++#define DPSECI_CMDID_GET_IRQ_STATUS DPSECI_CMD_V1(0x016)
++#define DPSECI_CMDID_CLEAR_IRQ_STATUS DPSECI_CMD_V1(0x017)
++
++#define DPSECI_CMDID_SET_RX_QUEUE DPSECI_CMD_V1(0x194)
++#define DPSECI_CMDID_GET_RX_QUEUE DPSECI_CMD_V1(0x196)
++#define DPSECI_CMDID_GET_TX_QUEUE DPSECI_CMD_V1(0x197)
++#define DPSECI_CMDID_GET_SEC_ATTR DPSECI_CMD_V2(0x198)
++#define DPSECI_CMDID_GET_SEC_COUNTERS DPSECI_CMD_V1(0x199)
++#define DPSECI_CMDID_SET_OPR DPSECI_CMD_V1(0x19A)
++#define DPSECI_CMDID_GET_OPR DPSECI_CMD_V1(0x19B)
++#define DPSECI_CMDID_SET_CONGESTION_NOTIFICATION DPSECI_CMD_V1(0x170)
++#define DPSECI_CMDID_GET_CONGESTION_NOTIFICATION DPSECI_CMD_V1(0x171)
++
++/* Macros for accessing command fields smaller than 1 byte */
++#define DPSECI_MASK(field) \
++ GENMASK(DPSECI_##field##_SHIFT + DPSECI_##field##_SIZE - 1, \
++ DPSECI_##field##_SHIFT)
++
++#define dpseci_set_field(var, field, val) \
++ ((var) |= (((val) << DPSECI_##field##_SHIFT) & DPSECI_MASK(field)))
++
++#define dpseci_get_field(var, field) \
++ (((var) & DPSECI_MASK(field)) >> DPSECI_##field##_SHIFT)
++
++struct dpseci_cmd_open {
++ __le32 dpseci_id;
++};
++
++struct dpseci_cmd_create {
++ u8 priorities[8];
++ u8 num_tx_queues;
++ u8 num_rx_queues;
++ u8 pad0[6];
++ __le32 options;
++ __le32 pad1;
++ u8 priorities2[8];
++};
++
++struct dpseci_cmd_destroy {
++ __le32 object_id;
++};
++
++#define DPSECI_ENABLE_SHIFT 0
++#define DPSECI_ENABLE_SIZE 1
++
++struct dpseci_rsp_is_enabled {
++ u8 is_enabled;
++};
++
++struct dpseci_cmd_irq_enable {
++ u8 enable_state;
++ u8 pad[3];
++ u8 irq_index;
++};
++
++struct dpseci_rsp_get_irq_enable {
++ u8 enable_state;
++};
++
++struct dpseci_cmd_irq_mask {
++ __le32 mask;
++ u8 irq_index;
++};
++
++struct dpseci_cmd_irq_status {
++ __le32 status;
++ u8 irq_index;
++};
++
++struct dpseci_rsp_get_attributes {
++ __le32 id;
++ __le32 pad0;
++ u8 num_tx_queues;
++ u8 num_rx_queues;
++ u8 pad1[6];
++ __le32 options;
++};
++
++#define DPSECI_DEST_TYPE_SHIFT 0
++#define DPSECI_DEST_TYPE_SIZE 4
++
++#define DPSECI_ORDER_PRESERVATION_SHIFT 0
++#define DPSECI_ORDER_PRESERVATION_SIZE 1
++
++struct dpseci_cmd_queue {
++ __le32 dest_id;
++ u8 priority;
++ u8 queue;
++ u8 dest_type;
++ u8 pad;
++ __le64 user_ctx;
++ union {
++ __le32 options;
++ __le32 fqid;
++ };
++ u8 order_preservation_en;
++};
++
++struct dpseci_rsp_get_tx_queue {
++ __le32 pad;
++ __le32 fqid;
++ u8 priority;
++};
++
++struct dpseci_rsp_get_sec_attr {
++ __le16 ip_id;
++ u8 major_rev;
++ u8 minor_rev;
++ u8 era;
++ u8 pad0[3];
++ u8 deco_num;
++ u8 zuc_auth_acc_num;
++ u8 zuc_enc_acc_num;
++ u8 pad1;
++ u8 snow_f8_acc_num;
++ u8 snow_f9_acc_num;
++ u8 crc_acc_num;
++ u8 pad2;
++ u8 pk_acc_num;
++ u8 kasumi_acc_num;
++ u8 rng_acc_num;
++ u8 pad3;
++ u8 md_acc_num;
++ u8 arc4_acc_num;
++ u8 des_acc_num;
++ u8 aes_acc_num;
++ u8 ccha_acc_num;
++ u8 ptha_acc_num;
++};
++
++struct dpseci_rsp_get_sec_counters {
++ __le64 dequeued_requests;
++ __le64 ob_enc_requests;
++ __le64 ib_dec_requests;
++ __le64 ob_enc_bytes;
++ __le64 ob_prot_bytes;
++ __le64 ib_dec_bytes;
++ __le64 ib_valid_bytes;
++};
++
++struct dpseci_rsp_get_api_version {
++ __le16 major;
++ __le16 minor;
++};
++
++struct dpseci_cmd_opr {
++ __le16 pad;
++ u8 index;
++ u8 options;
++ u8 pad1[7];
++ u8 oloe;
++ u8 oeane;
++ u8 olws;
++ u8 oa;
++ u8 oprrws;
++};
++
++#define DPSECI_OPR_RIP_SHIFT 0
++#define DPSECI_OPR_RIP_SIZE 1
++#define DPSECI_OPR_ENABLE_SHIFT 1
++#define DPSECI_OPR_ENABLE_SIZE 1
++#define DPSECI_OPR_TSEQ_NLIS_SHIFT 0
++#define DPSECI_OPR_TSEQ_NLIS_SIZE 1
++#define DPSECI_OPR_HSEQ_NLIS_SHIFT 0
++#define DPSECI_OPR_HSEQ_NLIS_SIZE 1
++
++struct dpseci_rsp_get_opr {
++ __le64 pad;
++ u8 flags;
++ u8 pad0[2];
++ u8 oloe;
++ u8 oeane;
++ u8 olws;
++ u8 oa;
++ u8 oprrws;
++ __le16 nesn;
++ __le16 pad1;
++ __le16 ndsn;
++ __le16 pad2;
++ __le16 ea_tseq;
++ u8 tseq_nlis;
++ u8 pad3;
++ __le16 ea_hseq;
++ u8 hseq_nlis;
++ u8 pad4;
++ __le16 ea_hptr;
++ __le16 pad5;
++ __le16 ea_tptr;
++ __le16 pad6;
++ __le16 opr_vid;
++ __le16 pad7;
++ __le16 opr_id;
++};
++
++#define DPSECI_CGN_DEST_TYPE_SHIFT 0
++#define DPSECI_CGN_DEST_TYPE_SIZE 4
++#define DPSECI_CGN_UNITS_SHIFT 4
++#define DPSECI_CGN_UNITS_SIZE 2
++
++struct dpseci_cmd_congestion_notification {
++ __le32 dest_id;
++ __le16 notification_mode;
++ u8 priority;
++ u8 options;
++ __le64 message_iova;
++ __le64 message_ctx;
++ __le32 threshold_entry;
++ __le32 threshold_exit;
++};
++
++#endif /* _DPSECI_CMD_H_ */
+--- a/drivers/crypto/caam/error.c
++++ b/drivers/crypto/caam/error.c
+@@ -108,6 +108,54 @@ static const struct {
+ { 0xF1, "3GPP HFN matches or exceeds the Threshold" },
+ };
+
++static const struct {
++ u8 value;
++ const char *error_text;
++} qi_error_list[] = {
++ { 0x1F, "Job terminated by FQ or ICID flush" },
++ { 0x20, "FD format error"},
++ { 0x21, "FD command format error"},
++ { 0x23, "FL format error"},
++ { 0x25, "CRJD specified in FD, but not enabled in FLC"},
++ { 0x30, "Max. buffer size too small"},
++ { 0x31, "DHR exceeds max. buffer size (allocate mode, S/G format)"},
++ { 0x32, "SGT exceeds max. buffer size (allocate mode, S/G format"},
++ { 0x33, "Size over/underflow (allocate mode)"},
++ { 0x34, "Size over/underflow (reuse mode)"},
++ { 0x35, "Length exceeds max. short length (allocate mode, S/G/ format)"},
++ { 0x36, "Memory footprint exceeds max. value (allocate mode, S/G/ format)"},
++ { 0x41, "SBC frame format not supported (allocate mode)"},
++ { 0x42, "Pool 0 invalid / pool 1 size < pool 0 size (allocate mode)"},
++ { 0x43, "Annotation output enabled but ASAR = 0 (allocate mode)"},
++ { 0x44, "Unsupported or reserved frame format or SGHR = 1 (reuse mode)"},
++ { 0x45, "DHR correction underflow (reuse mode, single buffer format)"},
++ { 0x46, "Annotation length exceeds offset (reuse mode)"},
++ { 0x48, "Annotation output enabled but ASA limited by ASAR (reuse mode)"},
++ { 0x49, "Data offset correction exceeds input frame data length (reuse mode)"},
++ { 0x4B, "Annotation output enabled but ASA cannote be expanded (frame list)"},
++ { 0x51, "Unsupported IF reuse mode"},
++ { 0x52, "Unsupported FL use mode"},
++ { 0x53, "Unsupported RJD use mode"},
++ { 0x54, "Unsupported inline descriptor use mode"},
++ { 0xC0, "Table buffer pool 0 depletion"},
++ { 0xC1, "Table buffer pool 1 depletion"},
++ { 0xC2, "Data buffer pool 0 depletion, no OF allocated"},
++ { 0xC3, "Data buffer pool 1 depletion, no OF allocated"},
++ { 0xC4, "Data buffer pool 0 depletion, partial OF allocated"},
++ { 0xC5, "Data buffer pool 1 depletion, partial OF allocated"},
++ { 0xD0, "FLC read error"},
++ { 0xD1, "FL read error"},
++ { 0xD2, "FL write error"},
++ { 0xD3, "OF SGT write error"},
++ { 0xD4, "PTA read error"},
++ { 0xD5, "PTA write error"},
++ { 0xD6, "OF SGT F-bit write error"},
++ { 0xD7, "ASA write error"},
++ { 0xE1, "FLC[ICR]=0 ICID error"},
++ { 0xE2, "FLC[ICR]=1 ICID error"},
++ { 0xE4, "source of ICID flush not trusted (BDI = 0)"},
++};
++
+ static const char * const cha_id_list[] = {
+ "",
+ "AES",
+@@ -236,6 +284,27 @@ static void report_deco_status(struct de
+ status, error, idx_str, idx, err_str, err_err_code);
+ }
+
++static void report_qi_status(struct device *qidev, const u32 status,
++ const char *error)
++{
++ u8 err_id = status & JRSTA_QIERR_ERROR_MASK;
++ const char *err_str = "unidentified error value 0x";
++ char err_err_code[3] = { 0 };
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(qi_error_list); i++)
++ if (qi_error_list[i].value == err_id)
++ break;
++
++ if (i != ARRAY_SIZE(qi_error_list) && qi_error_list[i].error_text)
++ err_str = qi_error_list[i].error_text;
++ else
++ snprintf(err_err_code, sizeof(err_err_code), "%02x", err_id);
++
++ dev_err(qidev, "%08x: %s: %s%s\n",
++ status, error, err_str, err_err_code);
++}
++
+ static void report_jr_status(struct device *jrdev, const u32 status,
+ const char *error)
+ {
+@@ -250,7 +319,7 @@ static void report_cond_code_status(stru
+ status, error, __func__);
+ }
+
+-void caam_jr_strstatus(struct device *jrdev, u32 status)
++void caam_strstatus(struct device *jrdev, u32 status, bool qi_v2)
+ {
+ static const struct stat_src {
+ void (*report_ssed)(struct device *jrdev, const u32 status,
+@@ -262,7 +331,7 @@ void caam_jr_strstatus(struct device *jr
+ { report_ccb_status, "CCB" },
+ { report_jump_status, "Jump" },
+ { report_deco_status, "DECO" },
+- { NULL, "Queue Manager Interface" },
++ { report_qi_status, "Queue Manager Interface" },
+ { report_jr_status, "Job Ring" },
+ { report_cond_code_status, "Condition Code" },
+ { NULL, NULL },
+@@ -288,4 +357,4 @@ void caam_jr_strstatus(struct device *jr
+ else
+ dev_err(jrdev, "%d: unknown error source\n", ssrc);
+ }
+-EXPORT_SYMBOL(caam_jr_strstatus);
++EXPORT_SYMBOL(caam_strstatus);
+--- a/drivers/crypto/caam/error.h
++++ b/drivers/crypto/caam/error.h
+@@ -8,7 +8,11 @@
+ #ifndef CAAM_ERROR_H
+ #define CAAM_ERROR_H
+ #define CAAM_ERROR_STR_MAX 302
+-void caam_jr_strstatus(struct device *jrdev, u32 status);
++
++void caam_strstatus(struct device *dev, u32 status, bool qi_v2);
++
++#define caam_jr_strstatus(jrdev, status) caam_strstatus(jrdev, status, false)
++#define caam_qi2_strstatus(qidev, status) caam_strstatus(qidev, status, true)
+
+ void caam_dump_sg(const char *level, const char *prefix_str, int prefix_type,
+ int rowsize, int groupsize, struct scatterlist *sg,
+--- a/drivers/crypto/caam/intern.h
++++ b/drivers/crypto/caam/intern.h
+@@ -84,6 +84,7 @@ struct caam_drv_private {
+ u8 qi_present; /* Nonzero if QI present in device */
+ int secvio_irq; /* Security violation interrupt number */
+ int virt_en; /* Virtualization enabled in CAAM */
++ int era; /* CAAM Era (internal HW revision) */
+
+ #define RNG4_MAX_HANDLES 2
+ /* RNG4 block */
+--- a/drivers/crypto/caam/jr.c
++++ b/drivers/crypto/caam/jr.c
+@@ -23,6 +23,14 @@ struct jr_driver_data {
+
+ static struct jr_driver_data driver_data;
+
++static int jr_driver_probed;
++
++int caam_jr_driver_probed(void)
++{
++ return jr_driver_probed;
++}
++EXPORT_SYMBOL(caam_jr_driver_probed);
++
+ static int caam_reset_hw_jr(struct device *dev)
+ {
+ struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
+@@ -119,6 +127,8 @@ static int caam_jr_remove(struct platfor
+ dev_err(jrdev, "Failed to shut down job ring\n");
+ irq_dispose_mapping(jrpriv->irq);
+
++ jr_driver_probed--;
++
+ return ret;
+ }
+
+@@ -282,6 +292,36 @@ struct device *caam_jr_alloc(void)
+ EXPORT_SYMBOL(caam_jr_alloc);
+
+ /**
++ * caam_jridx_alloc() - Alloc a specific job ring based on its index.
++ *
++ * returns : pointer to the newly allocated physical
++ * JobR dev can be written to if successful.
++ **/
++struct device *caam_jridx_alloc(int idx)
++{
++ struct caam_drv_private_jr *jrpriv;
++ struct device *dev = ERR_PTR(-ENODEV);
++
++ spin_lock(&driver_data.jr_alloc_lock);
++
++ if (list_empty(&driver_data.jr_list))
++ goto end;
++
++ list_for_each_entry(jrpriv, &driver_data.jr_list, list_node) {
++ if (jrpriv->ridx == idx) {
++ atomic_inc(&jrpriv->tfm_count);
++ dev = jrpriv->dev;
++ break;
++ }
++ }
++
++end:
++ spin_unlock(&driver_data.jr_alloc_lock);
++ return dev;
++}
++EXPORT_SYMBOL(caam_jridx_alloc);
++
++/**
+ * caam_jr_free() - Free the Job Ring
+ * @rdev - points to the dev that identifies the Job ring to
+ * be released.
+@@ -539,6 +579,8 @@ static int caam_jr_probe(struct platform
+
+ atomic_set(&jrpriv->tfm_count, 0);
+
++ jr_driver_probed++;
++
+ return 0;
+ }
+
+--- a/drivers/crypto/caam/jr.h
++++ b/drivers/crypto/caam/jr.h
+@@ -9,7 +9,9 @@
+ #define JR_H
+
+ /* Prototypes for backend-level services exposed to APIs */
++int caam_jr_driver_probed(void);
+ struct device *caam_jr_alloc(void);
++struct device *caam_jridx_alloc(int idx);
+ void caam_jr_free(struct device *rdev);
+ int caam_jr_enqueue(struct device *dev, u32 *desc,
+ void (*cbk)(struct device *dev, u32 *desc, u32 status,
+--- a/drivers/crypto/caam/key_gen.c
++++ b/drivers/crypto/caam/key_gen.c
+@@ -11,36 +11,6 @@
+ #include "desc_constr.h"
+ #include "key_gen.h"
+
+-/**
+- * split_key_len - Compute MDHA split key length for a given algorithm
+- * @hash: Hashing algorithm selection, one of OP_ALG_ALGSEL_* - MD5, SHA1,
+- * SHA224, SHA384, SHA512.
+- *
+- * Return: MDHA split key length
+- */
+-static inline u32 split_key_len(u32 hash)
+-{
+- /* Sizes for MDHA pads (*not* keys): MD5, SHA1, 224, 256, 384, 512 */
+- static const u8 mdpadlen[] = { 16, 20, 32, 32, 64, 64 };
+- u32 idx;
+-
+- idx = (hash & OP_ALG_ALGSEL_SUBMASK) >> OP_ALG_ALGSEL_SHIFT;
+-
+- return (u32)(mdpadlen[idx] * 2);
+-}
+-
+-/**
+- * split_key_pad_len - Compute MDHA split key pad length for a given algorithm
+- * @hash: Hashing algorithm selection, one of OP_ALG_ALGSEL_* - MD5, SHA1,
+- * SHA224, SHA384, SHA512.
+- *
+- * Return: MDHA split key pad length
+- */
+-static inline u32 split_key_pad_len(u32 hash)
+-{
+- return ALIGN(split_key_len(hash), 16);
+-}
+-
+ void split_key_done(struct device *dev, u32 *desc, u32 err,
+ void *context)
+ {
+--- a/drivers/crypto/caam/key_gen.h
++++ b/drivers/crypto/caam/key_gen.h
+@@ -6,6 +6,36 @@
+ *
+ */
+
++/**
++ * split_key_len - Compute MDHA split key length for a given algorithm
++ * @hash: Hashing algorithm selection, one of OP_ALG_ALGSEL_* - MD5, SHA1,
++ * SHA224, SHA384, SHA512.
++ *
++ * Return: MDHA split key length
++ */
++static inline u32 split_key_len(u32 hash)
++{
++ /* Sizes for MDHA pads (*not* keys): MD5, SHA1, 224, 256, 384, 512 */
++ static const u8 mdpadlen[] = { 16, 20, 32, 32, 64, 64 };
++ u32 idx;
++
++ idx = (hash & OP_ALG_ALGSEL_SUBMASK) >> OP_ALG_ALGSEL_SHIFT;
++
++ return (u32)(mdpadlen[idx] * 2);
++}
++
++/**
++ * split_key_pad_len - Compute MDHA split key pad length for a given algorithm
++ * @hash: Hashing algorithm selection, one of OP_ALG_ALGSEL_* - MD5, SHA1,
++ * SHA224, SHA384, SHA512.
++ *
++ * Return: MDHA split key pad length
++ */
++static inline u32 split_key_pad_len(u32 hash)
++{
++ return ALIGN(split_key_len(hash), 16);
++}
++
+ struct split_key_result {
+ struct completion completion;
+ int err;
+--- a/drivers/crypto/caam/qi.c
++++ b/drivers/crypto/caam/qi.c
+@@ -9,7 +9,7 @@
+
+ #include <linux/cpumask.h>
+ #include <linux/kthread.h>
+-#include <soc/fsl/qman.h>
++#include <linux/fsl_qman.h>
+
+ #include "regs.h"
+ #include "qi.h"
+@@ -105,23 +105,21 @@ static struct kmem_cache *qi_cache;
+ int caam_qi_enqueue(struct device *qidev, struct caam_drv_req *req)
+ {
+ struct qm_fd fd;
+- dma_addr_t addr;
+ int ret;
+ int num_retries = 0;
+
+- qm_fd_clear_fd(&fd);
+- qm_fd_set_compound(&fd, qm_sg_entry_get_len(&req->fd_sgt[1]));
+-
+- addr = dma_map_single(qidev, req->fd_sgt, sizeof(req->fd_sgt),
++ fd.cmd = 0;
++ fd.format = qm_fd_compound;
++ fd.cong_weight = caam32_to_cpu(req->fd_sgt[1].length);
++ fd.addr = dma_map_single(qidev, req->fd_sgt, sizeof(req->fd_sgt),
+ DMA_BIDIRECTIONAL);
+- if (dma_mapping_error(qidev, addr)) {
++ if (dma_mapping_error(qidev, fd.addr)) {
+ dev_err(qidev, "DMA mapping error for QI enqueue request\n");
+ return -EIO;
+ }
+- qm_fd_addr_set64(&fd, addr);
+
+ do {
+- ret = qman_enqueue(req->drv_ctx->req_fq, &fd);
++ ret = qman_enqueue(req->drv_ctx->req_fq, &fd, 0);
+ if (likely(!ret))
+ return 0;
+
+@@ -137,7 +135,7 @@ int caam_qi_enqueue(struct device *qidev
+ EXPORT_SYMBOL(caam_qi_enqueue);
+
+ static void caam_fq_ern_cb(struct qman_portal *qm, struct qman_fq *fq,
+- const union qm_mr_entry *msg)
++ const struct qm_mr_entry *msg)
+ {
+ const struct qm_fd *fd;
+ struct caam_drv_req *drv_req;
+@@ -145,7 +143,7 @@ static void caam_fq_ern_cb(struct qman_p
+
+ fd = &msg->ern.fd;
+
+- if (qm_fd_get_format(fd) != qm_fd_compound) {
++ if (fd->format != qm_fd_compound) {
+ dev_err(qidev, "Non-compound FD from CAAM\n");
+ return;
+ }
+@@ -180,20 +178,22 @@ static struct qman_fq *create_caam_req_f
+ req_fq->cb.fqs = NULL;
+
+ ret = qman_create_fq(0, QMAN_FQ_FLAG_DYNAMIC_FQID |
+- QMAN_FQ_FLAG_TO_DCPORTAL, req_fq);
++ QMAN_FQ_FLAG_TO_DCPORTAL | QMAN_FQ_FLAG_LOCKED,
++ req_fq);
+ if (ret) {
+ dev_err(qidev, "Failed to create session req FQ\n");
+ goto create_req_fq_fail;
+ }
+
+- memset(&opts, 0, sizeof(opts));
+- opts.we_mask = cpu_to_be16(QM_INITFQ_WE_FQCTRL | QM_INITFQ_WE_DESTWQ |
+- QM_INITFQ_WE_CONTEXTB |
+- QM_INITFQ_WE_CONTEXTA | QM_INITFQ_WE_CGID);
+- opts.fqd.fq_ctrl = cpu_to_be16(QM_FQCTRL_CPCSTASH | QM_FQCTRL_CGE);
+- qm_fqd_set_destwq(&opts.fqd, qm_channel_caam, 2);
+- opts.fqd.context_b = cpu_to_be32(qman_fq_fqid(rsp_fq));
+- qm_fqd_context_a_set64(&opts.fqd, hwdesc);
++ opts.we_mask = QM_INITFQ_WE_FQCTRL | QM_INITFQ_WE_DESTWQ |
++ QM_INITFQ_WE_CONTEXTB | QM_INITFQ_WE_CONTEXTA |
++ QM_INITFQ_WE_CGID;
++ opts.fqd.fq_ctrl = QM_FQCTRL_CPCSTASH | QM_FQCTRL_CGE;
++ opts.fqd.dest.channel = qm_channel_caam;
++ opts.fqd.dest.wq = 2;
++ opts.fqd.context_b = qman_fq_fqid(rsp_fq);
++ opts.fqd.context_a.hi = upper_32_bits(hwdesc);
++ opts.fqd.context_a.lo = lower_32_bits(hwdesc);
+ opts.fqd.cgid = qipriv.cgr.cgrid;
+
+ ret = qman_init_fq(req_fq, fq_sched_flag, &opts);
+@@ -207,7 +207,7 @@ static struct qman_fq *create_caam_req_f
+ return req_fq;
+
+ init_req_fq_fail:
+- qman_destroy_fq(req_fq);
++ qman_destroy_fq(req_fq, 0);
+ create_req_fq_fail:
+ kfree(req_fq);
+ return ERR_PTR(ret);
+@@ -275,7 +275,7 @@ empty_fq:
+ if (ret)
+ dev_err(qidev, "OOS of FQID: %u failed\n", fq->fqid);
+
+- qman_destroy_fq(fq);
++ qman_destroy_fq(fq, 0);
+ kfree(fq);
+
+ return ret;
+@@ -292,7 +292,7 @@ static int empty_caam_fq(struct qman_fq
+ if (ret)
+ return ret;
+
+- if (!qm_mcr_np_get(&np, frm_cnt))
++ if (!np.frm_cnt)
+ break;
+
+ msleep(20);
+@@ -572,22 +572,27 @@ static enum qman_cb_dqrr_result caam_rsp
+ struct caam_drv_req *drv_req;
+ const struct qm_fd *fd;
+ struct device *qidev = &(raw_cpu_ptr(&pcpu_qipriv)->net_dev.dev);
+- u32 status;
+
+ if (caam_qi_napi_schedule(p, caam_napi))
+ return qman_cb_dqrr_stop;
+
+ fd = &dqrr->fd;
+- status = be32_to_cpu(fd->status);
+- if (unlikely(status))
+- dev_err(qidev, "Error: %#x in CAAM response FD\n", status);
++ if (unlikely(fd->status)) {
++ u32 ssrc = fd->status & JRSTA_SSRC_MASK;
++ u8 err_id = fd->status & JRSTA_CCBERR_ERRID_MASK;
++
++ if (ssrc != JRSTA_SSRC_CCB_ERROR ||
++ err_id != JRSTA_CCBERR_ERRID_ICVCHK)
++ dev_err(qidev, "Error: %#x in CAAM response FD\n",
++ fd->status);
++ }
+
+- if (unlikely(qm_fd_get_format(fd) != qm_fd_compound)) {
++ if (unlikely(fd->format != qm_fd_compound)) {
+ dev_err(qidev, "Non-compound FD from CAAM\n");
+ return qman_cb_dqrr_consume;
+ }
+
+- drv_req = (struct caam_drv_req *)phys_to_virt(qm_fd_addr_get64(fd));
++ drv_req = (struct caam_drv_req *)phys_to_virt(fd->addr);
+ if (unlikely(!drv_req)) {
+ dev_err(qidev,
+ "Can't find original request for caam response\n");
+@@ -597,7 +602,7 @@ static enum qman_cb_dqrr_result caam_rsp
+ dma_unmap_single(drv_req->drv_ctx->qidev, qm_fd_addr(fd),
+ sizeof(drv_req->fd_sgt), DMA_BIDIRECTIONAL);
+
+- drv_req->cbk(drv_req, status);
++ drv_req->cbk(drv_req, fd->status);
+ return qman_cb_dqrr_consume;
+ }
+
+@@ -621,17 +626,18 @@ static int alloc_rsp_fq_cpu(struct devic
+ return -ENODEV;
+ }
+
+- memset(&opts, 0, sizeof(opts));
+- opts.we_mask = cpu_to_be16(QM_INITFQ_WE_FQCTRL | QM_INITFQ_WE_DESTWQ |
+- QM_INITFQ_WE_CONTEXTB |
+- QM_INITFQ_WE_CONTEXTA | QM_INITFQ_WE_CGID);
+- opts.fqd.fq_ctrl = cpu_to_be16(QM_FQCTRL_CTXASTASHING |
+- QM_FQCTRL_CPCSTASH | QM_FQCTRL_CGE);
+- qm_fqd_set_destwq(&opts.fqd, qman_affine_channel(cpu), 3);
++ opts.we_mask = QM_INITFQ_WE_FQCTRL | QM_INITFQ_WE_DESTWQ |
++ QM_INITFQ_WE_CONTEXTB | QM_INITFQ_WE_CONTEXTA |
++ QM_INITFQ_WE_CGID;
++ opts.fqd.fq_ctrl = QM_FQCTRL_CTXASTASHING | QM_FQCTRL_CPCSTASH |
++ QM_FQCTRL_CGE;
++ opts.fqd.dest.channel = qman_affine_channel(cpu);
++ opts.fqd.dest.wq = 3;
+ opts.fqd.cgid = qipriv.cgr.cgrid;
+ opts.fqd.context_a.stashing.exclusive = QM_STASHING_EXCL_CTX |
+ QM_STASHING_EXCL_DATA;
+- qm_fqd_set_stashing(&opts.fqd, 0, 1, 1);
++ opts.fqd.context_a.stashing.data_cl = 1;
++ opts.fqd.context_a.stashing.context_cl = 1;
+
+ ret = qman_init_fq(fq, QMAN_INITFQ_FLAG_SCHED, &opts);
+ if (ret) {
+@@ -662,8 +668,7 @@ static int init_cgr(struct device *qidev
+
+ qipriv.cgr.cb = cgr_cb;
+ memset(&opts, 0, sizeof(opts));
+- opts.we_mask = cpu_to_be16(QM_CGR_WE_CSCN_EN | QM_CGR_WE_CS_THRES |
+- QM_CGR_WE_MODE);
++ opts.we_mask = QM_CGR_WE_CSCN_EN | QM_CGR_WE_CS_THRES | QM_CGR_WE_MODE;
+ opts.cgr.cscn_en = QM_CGR_EN;
+ opts.cgr.mode = QMAN_CGR_MODE_FRAME;
+ qm_cgr_cs_thres_set64(&opts.cgr.cs_thres, val, 1);
+--- a/drivers/crypto/caam/qi.h
++++ b/drivers/crypto/caam/qi.h
+@@ -9,7 +9,7 @@
+ #ifndef __QI_H__
+ #define __QI_H__
+
+-#include <soc/fsl/qman.h>
++#include <linux/fsl_qman.h>
+ #include "compat.h"
+ #include "desc.h"
+ #include "desc_constr.h"
+--- a/drivers/crypto/caam/regs.h
++++ b/drivers/crypto/caam/regs.h
+@@ -627,6 +627,8 @@ struct caam_job_ring {
+ #define JRSTA_DECOERR_INVSIGN 0x86
+ #define JRSTA_DECOERR_DSASIGN 0x87
+
++#define JRSTA_QIERR_ERROR_MASK 0x00ff
++
+ #define JRSTA_CCBERR_JUMP 0x08000000
+ #define JRSTA_CCBERR_INDEX_MASK 0xff00
+ #define JRSTA_CCBERR_INDEX_SHIFT 8
+--- a/drivers/crypto/caam/sg_sw_qm.h
++++ b/drivers/crypto/caam/sg_sw_qm.h
+@@ -34,46 +34,61 @@
+ #ifndef __SG_SW_QM_H
+ #define __SG_SW_QM_H
+
+-#include <soc/fsl/qman.h>
++#include <linux/fsl_qman.h>
+ #include "regs.h"
+
++static inline void cpu_to_hw_sg(struct qm_sg_entry *qm_sg_ptr)
++{
++ dma_addr_t addr = qm_sg_ptr->opaque;
++
++ qm_sg_ptr->opaque = cpu_to_caam64(addr);
++ qm_sg_ptr->sgt_efl = cpu_to_caam32(qm_sg_ptr->sgt_efl);
++}
++
+ static inline void __dma_to_qm_sg(struct qm_sg_entry *qm_sg_ptr, dma_addr_t dma,
+- u16 offset)
++ u32 len, u16 offset)
+ {
+- qm_sg_entry_set64(qm_sg_ptr, dma);
++ qm_sg_ptr->addr = dma;
++ qm_sg_ptr->length = len;
+ qm_sg_ptr->__reserved2 = 0;
+ qm_sg_ptr->bpid = 0;
+- qm_sg_ptr->offset = cpu_to_be16(offset & QM_SG_OFF_MASK);
++ qm_sg_ptr->__reserved3 = 0;
++ qm_sg_ptr->offset = offset & QM_SG_OFFSET_MASK;
++
++ cpu_to_hw_sg(qm_sg_ptr);
+ }
+
+ static inline void dma_to_qm_sg_one(struct qm_sg_entry *qm_sg_ptr,
+ dma_addr_t dma, u32 len, u16 offset)
+ {
+- __dma_to_qm_sg(qm_sg_ptr, dma, offset);
+- qm_sg_entry_set_len(qm_sg_ptr, len);
++ qm_sg_ptr->extension = 0;
++ qm_sg_ptr->final = 0;
++ __dma_to_qm_sg(qm_sg_ptr, dma, len, offset);
+ }
+
+ static inline void dma_to_qm_sg_one_last(struct qm_sg_entry *qm_sg_ptr,
+ dma_addr_t dma, u32 len, u16 offset)
+ {
+- __dma_to_qm_sg(qm_sg_ptr, dma, offset);
+- qm_sg_entry_set_f(qm_sg_ptr, len);
++ qm_sg_ptr->extension = 0;
++ qm_sg_ptr->final = 1;
++ __dma_to_qm_sg(qm_sg_ptr, dma, len, offset);
+ }
+
+ static inline void dma_to_qm_sg_one_ext(struct qm_sg_entry *qm_sg_ptr,
+ dma_addr_t dma, u32 len, u16 offset)
+ {
+- __dma_to_qm_sg(qm_sg_ptr, dma, offset);
+- qm_sg_ptr->cfg = cpu_to_be32(QM_SG_EXT | (len & QM_SG_LEN_MASK));
++ qm_sg_ptr->extension = 1;
++ qm_sg_ptr->final = 0;
++ __dma_to_qm_sg(qm_sg_ptr, dma, len, offset);
+ }
+
+ static inline void dma_to_qm_sg_one_last_ext(struct qm_sg_entry *qm_sg_ptr,
+ dma_addr_t dma, u32 len,
+ u16 offset)
+ {
+- __dma_to_qm_sg(qm_sg_ptr, dma, offset);
+- qm_sg_ptr->cfg = cpu_to_be32(QM_SG_EXT | QM_SG_FIN |
+- (len & QM_SG_LEN_MASK));
++ qm_sg_ptr->extension = 1;
++ qm_sg_ptr->final = 1;
++ __dma_to_qm_sg(qm_sg_ptr, dma, len, offset);
+ }
+
+ /*
+@@ -102,7 +117,10 @@ static inline void sg_to_qm_sg_last(stru
+ struct qm_sg_entry *qm_sg_ptr, u16 offset)
+ {
+ qm_sg_ptr = sg_to_qm_sg(sg, sg_count, qm_sg_ptr, offset);
+- qm_sg_entry_set_f(qm_sg_ptr, qm_sg_entry_get_len(qm_sg_ptr));
++
++ qm_sg_ptr->sgt_efl = caam32_to_cpu(qm_sg_ptr->sgt_efl);
++ qm_sg_ptr->final = 1;
++ qm_sg_ptr->sgt_efl = cpu_to_caam32(qm_sg_ptr->sgt_efl);
+ }
+
+ #endif /* __SG_SW_QM_H */
+--- a/drivers/crypto/talitos.c
++++ b/drivers/crypto/talitos.c
+@@ -1241,6 +1241,14 @@ static int ipsec_esp(struct talitos_edes
+ ret = talitos_sg_map_ext(dev, areq->src, cryptlen, edesc, &desc->ptr[4],
+ sg_count, areq->assoclen, tbl_off, elen);
+
++ /*
++ * In case of SEC 2.x+, cipher in len must include only the ciphertext,
++ * while extent is used for ICV len.
++ */
++ if ((edesc->desc.hdr & DESC_HDR_TYPE_IPSEC_ESP) &&
++ (desc->hdr & DESC_HDR_MODE1_MDEU_CICV))
++ desc->ptr[4].len = cpu_to_be16(cryptlen);
++
+ if (ret > 1) {
+ tbl_off += ret;
+ sync_needed = true;