diff options
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.patch | 13093 |
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; |