162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * AES CCM routines supporting the Power 7+ Nest Accelerators driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2012 International Business Machines Inc.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author: Kent Yoder <yoder1@us.ibm.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <crypto/internal/aead.h>
1162306a36Sopenharmony_ci#include <crypto/aes.h>
1262306a36Sopenharmony_ci#include <crypto/algapi.h>
1362306a36Sopenharmony_ci#include <crypto/scatterwalk.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/types.h>
1662306a36Sopenharmony_ci#include <linux/crypto.h>
1762306a36Sopenharmony_ci#include <asm/vio.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "nx_csbcpb.h"
2062306a36Sopenharmony_ci#include "nx.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic int ccm_aes_nx_set_key(struct crypto_aead *tfm,
2462306a36Sopenharmony_ci			      const u8           *in_key,
2562306a36Sopenharmony_ci			      unsigned int        key_len)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base);
2862306a36Sopenharmony_ci	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
2962306a36Sopenharmony_ci	struct nx_csbcpb *csbcpb_aead = nx_ctx->csbcpb_aead;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	nx_ctx_init(nx_ctx, HCOP_FC_AES);
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	switch (key_len) {
3462306a36Sopenharmony_ci	case AES_KEYSIZE_128:
3562306a36Sopenharmony_ci		NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
3662306a36Sopenharmony_ci		NX_CPB_SET_KEY_SIZE(csbcpb_aead, NX_KS_AES_128);
3762306a36Sopenharmony_ci		nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
3862306a36Sopenharmony_ci		break;
3962306a36Sopenharmony_ci	default:
4062306a36Sopenharmony_ci		return -EINVAL;
4162306a36Sopenharmony_ci	}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	csbcpb->cpb.hdr.mode = NX_MODE_AES_CCM;
4462306a36Sopenharmony_ci	memcpy(csbcpb->cpb.aes_ccm.key, in_key, key_len);
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	csbcpb_aead->cpb.hdr.mode = NX_MODE_AES_CCA;
4762306a36Sopenharmony_ci	memcpy(csbcpb_aead->cpb.aes_cca.key, in_key, key_len);
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	return 0;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic int ccm4309_aes_nx_set_key(struct crypto_aead *tfm,
5462306a36Sopenharmony_ci				  const u8           *in_key,
5562306a36Sopenharmony_ci				  unsigned int        key_len)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	if (key_len < 3)
6062306a36Sopenharmony_ci		return -EINVAL;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	key_len -= 3;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	memcpy(nx_ctx->priv.ccm.nonce, in_key + key_len, 3);
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	return ccm_aes_nx_set_key(tfm, in_key, key_len);
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic int ccm_aes_nx_setauthsize(struct crypto_aead *tfm,
7062306a36Sopenharmony_ci				  unsigned int authsize)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	switch (authsize) {
7362306a36Sopenharmony_ci	case 4:
7462306a36Sopenharmony_ci	case 6:
7562306a36Sopenharmony_ci	case 8:
7662306a36Sopenharmony_ci	case 10:
7762306a36Sopenharmony_ci	case 12:
7862306a36Sopenharmony_ci	case 14:
7962306a36Sopenharmony_ci	case 16:
8062306a36Sopenharmony_ci		break;
8162306a36Sopenharmony_ci	default:
8262306a36Sopenharmony_ci		return -EINVAL;
8362306a36Sopenharmony_ci	}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	return 0;
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic int ccm4309_aes_nx_setauthsize(struct crypto_aead *tfm,
8962306a36Sopenharmony_ci				      unsigned int authsize)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	switch (authsize) {
9262306a36Sopenharmony_ci	case 8:
9362306a36Sopenharmony_ci	case 12:
9462306a36Sopenharmony_ci	case 16:
9562306a36Sopenharmony_ci		break;
9662306a36Sopenharmony_ci	default:
9762306a36Sopenharmony_ci		return -EINVAL;
9862306a36Sopenharmony_ci	}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	return 0;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/* taken from crypto/ccm.c */
10462306a36Sopenharmony_cistatic int set_msg_len(u8 *block, unsigned int msglen, int csize)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	__be32 data;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	memset(block, 0, csize);
10962306a36Sopenharmony_ci	block += csize;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	if (csize >= 4)
11262306a36Sopenharmony_ci		csize = 4;
11362306a36Sopenharmony_ci	else if (msglen > (unsigned int)(1 << (8 * csize)))
11462306a36Sopenharmony_ci		return -EOVERFLOW;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	data = cpu_to_be32(msglen);
11762306a36Sopenharmony_ci	memcpy(block - csize, (u8 *)&data + 4 - csize, csize);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	return 0;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci/* taken from crypto/ccm.c */
12362306a36Sopenharmony_cistatic inline int crypto_ccm_check_iv(const u8 *iv)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	/* 2 <= L <= 8, so 1 <= L' <= 7. */
12662306a36Sopenharmony_ci	if (1 > iv[0] || iv[0] > 7)
12762306a36Sopenharmony_ci		return -EINVAL;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	return 0;
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci/* based on code from crypto/ccm.c */
13362306a36Sopenharmony_cistatic int generate_b0(u8 *iv, unsigned int assoclen, unsigned int authsize,
13462306a36Sopenharmony_ci		       unsigned int cryptlen, u8 *b0)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	unsigned int l, lp, m = authsize;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	memcpy(b0, iv, 16);
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	lp = b0[0];
14162306a36Sopenharmony_ci	l = lp + 1;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	/* set m, bits 3-5 */
14462306a36Sopenharmony_ci	*b0 |= (8 * ((m - 2) / 2));
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	/* set adata, bit 6, if associated data is used */
14762306a36Sopenharmony_ci	if (assoclen)
14862306a36Sopenharmony_ci		*b0 |= 64;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	return set_msg_len(b0 + 16 - l, cryptlen, l);
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cistatic int generate_pat(u8                   *iv,
15462306a36Sopenharmony_ci			struct aead_request  *req,
15562306a36Sopenharmony_ci			struct nx_crypto_ctx *nx_ctx,
15662306a36Sopenharmony_ci			unsigned int          authsize,
15762306a36Sopenharmony_ci			unsigned int          nbytes,
15862306a36Sopenharmony_ci			unsigned int	      assoclen,
15962306a36Sopenharmony_ci			u8                   *out)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	struct nx_sg *nx_insg = nx_ctx->in_sg;
16262306a36Sopenharmony_ci	struct nx_sg *nx_outsg = nx_ctx->out_sg;
16362306a36Sopenharmony_ci	unsigned int iauth_len = 0;
16462306a36Sopenharmony_ci	u8 tmp[16], *b1 = NULL, *b0 = NULL, *result = NULL;
16562306a36Sopenharmony_ci	int rc;
16662306a36Sopenharmony_ci	unsigned int max_sg_len;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	/* zero the ctr value */
16962306a36Sopenharmony_ci	memset(iv + 15 - iv[0], 0, iv[0] + 1);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	/* page 78 of nx_wb.pdf has,
17262306a36Sopenharmony_ci	 * Note: RFC3610 allows the AAD data to be up to 2^64 -1 bytes
17362306a36Sopenharmony_ci	 * in length. If a full message is used, the AES CCA implementation
17462306a36Sopenharmony_ci	 * restricts the maximum AAD length to 2^32 -1 bytes.
17562306a36Sopenharmony_ci	 * If partial messages are used, the implementation supports
17662306a36Sopenharmony_ci	 * 2^64 -1 bytes maximum AAD length.
17762306a36Sopenharmony_ci	 *
17862306a36Sopenharmony_ci	 * However, in the cryptoapi's aead_request structure,
17962306a36Sopenharmony_ci	 * assoclen is an unsigned int, thus it cannot hold a length
18062306a36Sopenharmony_ci	 * value greater than 2^32 - 1.
18162306a36Sopenharmony_ci	 * Thus the AAD is further constrained by this and is never
18262306a36Sopenharmony_ci	 * greater than 2^32.
18362306a36Sopenharmony_ci	 */
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (!assoclen) {
18662306a36Sopenharmony_ci		b0 = nx_ctx->csbcpb->cpb.aes_ccm.in_pat_or_b0;
18762306a36Sopenharmony_ci	} else if (assoclen <= 14) {
18862306a36Sopenharmony_ci		/* if associated data is 14 bytes or less, we do 1 GCM
18962306a36Sopenharmony_ci		 * operation on 2 AES blocks, B0 (stored in the csbcpb) and B1,
19062306a36Sopenharmony_ci		 * which is fed in through the source buffers here */
19162306a36Sopenharmony_ci		b0 = nx_ctx->csbcpb->cpb.aes_ccm.in_pat_or_b0;
19262306a36Sopenharmony_ci		b1 = nx_ctx->priv.ccm.iauth_tag;
19362306a36Sopenharmony_ci		iauth_len = assoclen;
19462306a36Sopenharmony_ci	} else if (assoclen <= 65280) {
19562306a36Sopenharmony_ci		/* if associated data is less than (2^16 - 2^8), we construct
19662306a36Sopenharmony_ci		 * B1 differently and feed in the associated data to a CCA
19762306a36Sopenharmony_ci		 * operation */
19862306a36Sopenharmony_ci		b0 = nx_ctx->csbcpb_aead->cpb.aes_cca.b0;
19962306a36Sopenharmony_ci		b1 = nx_ctx->csbcpb_aead->cpb.aes_cca.b1;
20062306a36Sopenharmony_ci		iauth_len = 14;
20162306a36Sopenharmony_ci	} else {
20262306a36Sopenharmony_ci		b0 = nx_ctx->csbcpb_aead->cpb.aes_cca.b0;
20362306a36Sopenharmony_ci		b1 = nx_ctx->csbcpb_aead->cpb.aes_cca.b1;
20462306a36Sopenharmony_ci		iauth_len = 10;
20562306a36Sopenharmony_ci	}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	/* generate B0 */
20862306a36Sopenharmony_ci	rc = generate_b0(iv, assoclen, authsize, nbytes, b0);
20962306a36Sopenharmony_ci	if (rc)
21062306a36Sopenharmony_ci		return rc;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	/* generate B1:
21362306a36Sopenharmony_ci	 * add control info for associated data
21462306a36Sopenharmony_ci	 * RFC 3610 and NIST Special Publication 800-38C
21562306a36Sopenharmony_ci	 */
21662306a36Sopenharmony_ci	if (b1) {
21762306a36Sopenharmony_ci		memset(b1, 0, 16);
21862306a36Sopenharmony_ci		if (assoclen <= 65280) {
21962306a36Sopenharmony_ci			*(u16 *)b1 = assoclen;
22062306a36Sopenharmony_ci			scatterwalk_map_and_copy(b1 + 2, req->src, 0,
22162306a36Sopenharmony_ci					 iauth_len, SCATTERWALK_FROM_SG);
22262306a36Sopenharmony_ci		} else {
22362306a36Sopenharmony_ci			*(u16 *)b1 = (u16)(0xfffe);
22462306a36Sopenharmony_ci			*(u32 *)&b1[2] = assoclen;
22562306a36Sopenharmony_ci			scatterwalk_map_and_copy(b1 + 6, req->src, 0,
22662306a36Sopenharmony_ci					 iauth_len, SCATTERWALK_FROM_SG);
22762306a36Sopenharmony_ci		}
22862306a36Sopenharmony_ci	}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	/* now copy any remaining AAD to scatterlist and call nx... */
23162306a36Sopenharmony_ci	if (!assoclen) {
23262306a36Sopenharmony_ci		return rc;
23362306a36Sopenharmony_ci	} else if (assoclen <= 14) {
23462306a36Sopenharmony_ci		unsigned int len = 16;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci		nx_insg = nx_build_sg_list(nx_insg, b1, &len, nx_ctx->ap->sglen);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci		if (len != 16)
23962306a36Sopenharmony_ci			return -EINVAL;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci		nx_outsg = nx_build_sg_list(nx_outsg, tmp, &len,
24262306a36Sopenharmony_ci					    nx_ctx->ap->sglen);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci		if (len != 16)
24562306a36Sopenharmony_ci			return -EINVAL;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci		/* inlen should be negative, indicating to phyp that its a
24862306a36Sopenharmony_ci		 * pointer to an sg list */
24962306a36Sopenharmony_ci		nx_ctx->op.inlen = (nx_ctx->in_sg - nx_insg) *
25062306a36Sopenharmony_ci					sizeof(struct nx_sg);
25162306a36Sopenharmony_ci		nx_ctx->op.outlen = (nx_ctx->out_sg - nx_outsg) *
25262306a36Sopenharmony_ci					sizeof(struct nx_sg);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci		NX_CPB_FDM(nx_ctx->csbcpb) |= NX_FDM_ENDE_ENCRYPT;
25562306a36Sopenharmony_ci		NX_CPB_FDM(nx_ctx->csbcpb) |= NX_FDM_INTERMEDIATE;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci		result = nx_ctx->csbcpb->cpb.aes_ccm.out_pat_or_mac;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci		rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
26062306a36Sopenharmony_ci				   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
26162306a36Sopenharmony_ci		if (rc)
26262306a36Sopenharmony_ci			return rc;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci		atomic_inc(&(nx_ctx->stats->aes_ops));
26562306a36Sopenharmony_ci		atomic64_add(assoclen, &nx_ctx->stats->aes_bytes);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	} else {
26862306a36Sopenharmony_ci		unsigned int processed = 0, to_process;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci		processed += iauth_len;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci		/* page_limit: number of sg entries that fit on one page */
27362306a36Sopenharmony_ci		max_sg_len = min_t(u64, nx_ctx->ap->sglen,
27462306a36Sopenharmony_ci				nx_driver.of.max_sg_len/sizeof(struct nx_sg));
27562306a36Sopenharmony_ci		max_sg_len = min_t(u64, max_sg_len,
27662306a36Sopenharmony_ci				nx_ctx->ap->databytelen/NX_PAGE_SIZE);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci		do {
27962306a36Sopenharmony_ci			to_process = min_t(u32, assoclen - processed,
28062306a36Sopenharmony_ci					   nx_ctx->ap->databytelen);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci			nx_insg = nx_walk_and_build(nx_ctx->in_sg,
28362306a36Sopenharmony_ci						    nx_ctx->ap->sglen,
28462306a36Sopenharmony_ci						    req->src, processed,
28562306a36Sopenharmony_ci						    &to_process);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci			if ((to_process + processed) < assoclen) {
28862306a36Sopenharmony_ci				NX_CPB_FDM(nx_ctx->csbcpb_aead) |=
28962306a36Sopenharmony_ci					NX_FDM_INTERMEDIATE;
29062306a36Sopenharmony_ci			} else {
29162306a36Sopenharmony_ci				NX_CPB_FDM(nx_ctx->csbcpb_aead) &=
29262306a36Sopenharmony_ci					~NX_FDM_INTERMEDIATE;
29362306a36Sopenharmony_ci			}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci			nx_ctx->op_aead.inlen = (nx_ctx->in_sg - nx_insg) *
29762306a36Sopenharmony_ci						sizeof(struct nx_sg);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci			result = nx_ctx->csbcpb_aead->cpb.aes_cca.out_pat_or_b0;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci			rc = nx_hcall_sync(nx_ctx, &nx_ctx->op_aead,
30262306a36Sopenharmony_ci				   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
30362306a36Sopenharmony_ci			if (rc)
30462306a36Sopenharmony_ci				return rc;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci			memcpy(nx_ctx->csbcpb_aead->cpb.aes_cca.b0,
30762306a36Sopenharmony_ci				nx_ctx->csbcpb_aead->cpb.aes_cca.out_pat_or_b0,
30862306a36Sopenharmony_ci				AES_BLOCK_SIZE);
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci			NX_CPB_FDM(nx_ctx->csbcpb_aead) |= NX_FDM_CONTINUATION;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci			atomic_inc(&(nx_ctx->stats->aes_ops));
31362306a36Sopenharmony_ci			atomic64_add(assoclen, &nx_ctx->stats->aes_bytes);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci			processed += to_process;
31662306a36Sopenharmony_ci		} while (processed < assoclen);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci		result = nx_ctx->csbcpb_aead->cpb.aes_cca.out_pat_or_b0;
31962306a36Sopenharmony_ci	}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	memcpy(out, result, AES_BLOCK_SIZE);
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	return rc;
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_cistatic int ccm_nx_decrypt(struct aead_request   *req,
32762306a36Sopenharmony_ci			  u8                    *iv,
32862306a36Sopenharmony_ci			  unsigned int assoclen)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
33162306a36Sopenharmony_ci	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
33262306a36Sopenharmony_ci	unsigned int nbytes = req->cryptlen;
33362306a36Sopenharmony_ci	unsigned int authsize = crypto_aead_authsize(crypto_aead_reqtfm(req));
33462306a36Sopenharmony_ci	struct nx_ccm_priv *priv = &nx_ctx->priv.ccm;
33562306a36Sopenharmony_ci	unsigned long irq_flags;
33662306a36Sopenharmony_ci	unsigned int processed = 0, to_process;
33762306a36Sopenharmony_ci	int rc = -1;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	spin_lock_irqsave(&nx_ctx->lock, irq_flags);
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	nbytes -= authsize;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	/* copy out the auth tag to compare with later */
34462306a36Sopenharmony_ci	scatterwalk_map_and_copy(priv->oauth_tag,
34562306a36Sopenharmony_ci				 req->src, nbytes + req->assoclen, authsize,
34662306a36Sopenharmony_ci				 SCATTERWALK_FROM_SG);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	rc = generate_pat(iv, req, nx_ctx, authsize, nbytes, assoclen,
34962306a36Sopenharmony_ci			  csbcpb->cpb.aes_ccm.in_pat_or_b0);
35062306a36Sopenharmony_ci	if (rc)
35162306a36Sopenharmony_ci		goto out;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	do {
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci		/* to_process: the AES_BLOCK_SIZE data chunk to process in this
35662306a36Sopenharmony_ci		 * update. This value is bound by sg list limits.
35762306a36Sopenharmony_ci		 */
35862306a36Sopenharmony_ci		to_process = nbytes - processed;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci		if ((to_process + processed) < nbytes)
36162306a36Sopenharmony_ci			NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
36262306a36Sopenharmony_ci		else
36362306a36Sopenharmony_ci			NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci		NX_CPB_FDM(nx_ctx->csbcpb) &= ~NX_FDM_ENDE_ENCRYPT;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci		rc = nx_build_sg_lists(nx_ctx, iv, req->dst, req->src,
36862306a36Sopenharmony_ci				       &to_process, processed + req->assoclen,
36962306a36Sopenharmony_ci				       csbcpb->cpb.aes_ccm.iv_or_ctr);
37062306a36Sopenharmony_ci		if (rc)
37162306a36Sopenharmony_ci			goto out;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci		rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
37462306a36Sopenharmony_ci			   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
37562306a36Sopenharmony_ci		if (rc)
37662306a36Sopenharmony_ci			goto out;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci		/* for partial completion, copy following for next
37962306a36Sopenharmony_ci		 * entry into loop...
38062306a36Sopenharmony_ci		 */
38162306a36Sopenharmony_ci		memcpy(iv, csbcpb->cpb.aes_ccm.out_ctr, AES_BLOCK_SIZE);
38262306a36Sopenharmony_ci		memcpy(csbcpb->cpb.aes_ccm.in_pat_or_b0,
38362306a36Sopenharmony_ci			csbcpb->cpb.aes_ccm.out_pat_or_mac, AES_BLOCK_SIZE);
38462306a36Sopenharmony_ci		memcpy(csbcpb->cpb.aes_ccm.in_s0,
38562306a36Sopenharmony_ci			csbcpb->cpb.aes_ccm.out_s0, AES_BLOCK_SIZE);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci		NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci		/* update stats */
39062306a36Sopenharmony_ci		atomic_inc(&(nx_ctx->stats->aes_ops));
39162306a36Sopenharmony_ci		atomic64_add(be32_to_cpu(csbcpb->csb.processed_byte_count),
39262306a36Sopenharmony_ci			     &(nx_ctx->stats->aes_bytes));
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci		processed += to_process;
39562306a36Sopenharmony_ci	} while (processed < nbytes);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	rc = crypto_memneq(csbcpb->cpb.aes_ccm.out_pat_or_mac, priv->oauth_tag,
39862306a36Sopenharmony_ci		    authsize) ? -EBADMSG : 0;
39962306a36Sopenharmony_ciout:
40062306a36Sopenharmony_ci	spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
40162306a36Sopenharmony_ci	return rc;
40262306a36Sopenharmony_ci}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_cistatic int ccm_nx_encrypt(struct aead_request   *req,
40562306a36Sopenharmony_ci			  u8                    *iv,
40662306a36Sopenharmony_ci			  unsigned int assoclen)
40762306a36Sopenharmony_ci{
40862306a36Sopenharmony_ci	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
40962306a36Sopenharmony_ci	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
41062306a36Sopenharmony_ci	unsigned int nbytes = req->cryptlen;
41162306a36Sopenharmony_ci	unsigned int authsize = crypto_aead_authsize(crypto_aead_reqtfm(req));
41262306a36Sopenharmony_ci	unsigned long irq_flags;
41362306a36Sopenharmony_ci	unsigned int processed = 0, to_process;
41462306a36Sopenharmony_ci	int rc = -1;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	spin_lock_irqsave(&nx_ctx->lock, irq_flags);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	rc = generate_pat(iv, req, nx_ctx, authsize, nbytes, assoclen,
41962306a36Sopenharmony_ci			  csbcpb->cpb.aes_ccm.in_pat_or_b0);
42062306a36Sopenharmony_ci	if (rc)
42162306a36Sopenharmony_ci		goto out;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	do {
42462306a36Sopenharmony_ci		/* to process: the AES_BLOCK_SIZE data chunk to process in this
42562306a36Sopenharmony_ci		 * update. This value is bound by sg list limits.
42662306a36Sopenharmony_ci		 */
42762306a36Sopenharmony_ci		to_process = nbytes - processed;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci		if ((to_process + processed) < nbytes)
43062306a36Sopenharmony_ci			NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
43162306a36Sopenharmony_ci		else
43262306a36Sopenharmony_ci			NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci		NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci		rc = nx_build_sg_lists(nx_ctx, iv, req->dst, req->src,
43762306a36Sopenharmony_ci				       &to_process, processed + req->assoclen,
43862306a36Sopenharmony_ci				       csbcpb->cpb.aes_ccm.iv_or_ctr);
43962306a36Sopenharmony_ci		if (rc)
44062306a36Sopenharmony_ci			goto out;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci		rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
44362306a36Sopenharmony_ci				   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
44462306a36Sopenharmony_ci		if (rc)
44562306a36Sopenharmony_ci			goto out;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci		/* for partial completion, copy following for next
44862306a36Sopenharmony_ci		 * entry into loop...
44962306a36Sopenharmony_ci		 */
45062306a36Sopenharmony_ci		memcpy(iv, csbcpb->cpb.aes_ccm.out_ctr, AES_BLOCK_SIZE);
45162306a36Sopenharmony_ci		memcpy(csbcpb->cpb.aes_ccm.in_pat_or_b0,
45262306a36Sopenharmony_ci			csbcpb->cpb.aes_ccm.out_pat_or_mac, AES_BLOCK_SIZE);
45362306a36Sopenharmony_ci		memcpy(csbcpb->cpb.aes_ccm.in_s0,
45462306a36Sopenharmony_ci			csbcpb->cpb.aes_ccm.out_s0, AES_BLOCK_SIZE);
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci		NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci		/* update stats */
45962306a36Sopenharmony_ci		atomic_inc(&(nx_ctx->stats->aes_ops));
46062306a36Sopenharmony_ci		atomic64_add(be32_to_cpu(csbcpb->csb.processed_byte_count),
46162306a36Sopenharmony_ci			     &(nx_ctx->stats->aes_bytes));
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci		processed += to_process;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	} while (processed < nbytes);
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	/* copy out the auth tag */
46862306a36Sopenharmony_ci	scatterwalk_map_and_copy(csbcpb->cpb.aes_ccm.out_pat_or_mac,
46962306a36Sopenharmony_ci				 req->dst, nbytes + req->assoclen, authsize,
47062306a36Sopenharmony_ci				 SCATTERWALK_TO_SG);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ciout:
47362306a36Sopenharmony_ci	spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
47462306a36Sopenharmony_ci	return rc;
47562306a36Sopenharmony_ci}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_cistatic int ccm4309_aes_nx_encrypt(struct aead_request *req)
47862306a36Sopenharmony_ci{
47962306a36Sopenharmony_ci	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
48062306a36Sopenharmony_ci	struct nx_gcm_rctx *rctx = aead_request_ctx(req);
48162306a36Sopenharmony_ci	u8 *iv = rctx->iv;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	iv[0] = 3;
48462306a36Sopenharmony_ci	memcpy(iv + 1, nx_ctx->priv.ccm.nonce, 3);
48562306a36Sopenharmony_ci	memcpy(iv + 4, req->iv, 8);
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	return ccm_nx_encrypt(req, iv, req->assoclen - 8);
48862306a36Sopenharmony_ci}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_cistatic int ccm_aes_nx_encrypt(struct aead_request *req)
49162306a36Sopenharmony_ci{
49262306a36Sopenharmony_ci	int rc;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	rc = crypto_ccm_check_iv(req->iv);
49562306a36Sopenharmony_ci	if (rc)
49662306a36Sopenharmony_ci		return rc;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	return ccm_nx_encrypt(req, req->iv, req->assoclen);
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_cistatic int ccm4309_aes_nx_decrypt(struct aead_request *req)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
50462306a36Sopenharmony_ci	struct nx_gcm_rctx *rctx = aead_request_ctx(req);
50562306a36Sopenharmony_ci	u8 *iv = rctx->iv;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	iv[0] = 3;
50862306a36Sopenharmony_ci	memcpy(iv + 1, nx_ctx->priv.ccm.nonce, 3);
50962306a36Sopenharmony_ci	memcpy(iv + 4, req->iv, 8);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	return ccm_nx_decrypt(req, iv, req->assoclen - 8);
51262306a36Sopenharmony_ci}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_cistatic int ccm_aes_nx_decrypt(struct aead_request *req)
51562306a36Sopenharmony_ci{
51662306a36Sopenharmony_ci	int rc;
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	rc = crypto_ccm_check_iv(req->iv);
51962306a36Sopenharmony_ci	if (rc)
52062306a36Sopenharmony_ci		return rc;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	return ccm_nx_decrypt(req, req->iv, req->assoclen);
52362306a36Sopenharmony_ci}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_cistruct aead_alg nx_ccm_aes_alg = {
52662306a36Sopenharmony_ci	.base = {
52762306a36Sopenharmony_ci		.cra_name        = "ccm(aes)",
52862306a36Sopenharmony_ci		.cra_driver_name = "ccm-aes-nx",
52962306a36Sopenharmony_ci		.cra_priority    = 300,
53062306a36Sopenharmony_ci		.cra_flags       = CRYPTO_ALG_NEED_FALLBACK,
53162306a36Sopenharmony_ci		.cra_blocksize   = 1,
53262306a36Sopenharmony_ci		.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
53362306a36Sopenharmony_ci		.cra_module      = THIS_MODULE,
53462306a36Sopenharmony_ci	},
53562306a36Sopenharmony_ci	.init        = nx_crypto_ctx_aes_ccm_init,
53662306a36Sopenharmony_ci	.exit        = nx_crypto_ctx_aead_exit,
53762306a36Sopenharmony_ci	.ivsize      = AES_BLOCK_SIZE,
53862306a36Sopenharmony_ci	.maxauthsize = AES_BLOCK_SIZE,
53962306a36Sopenharmony_ci	.setkey      = ccm_aes_nx_set_key,
54062306a36Sopenharmony_ci	.setauthsize = ccm_aes_nx_setauthsize,
54162306a36Sopenharmony_ci	.encrypt     = ccm_aes_nx_encrypt,
54262306a36Sopenharmony_ci	.decrypt     = ccm_aes_nx_decrypt,
54362306a36Sopenharmony_ci};
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_cistruct aead_alg nx_ccm4309_aes_alg = {
54662306a36Sopenharmony_ci	.base = {
54762306a36Sopenharmony_ci		.cra_name        = "rfc4309(ccm(aes))",
54862306a36Sopenharmony_ci		.cra_driver_name = "rfc4309-ccm-aes-nx",
54962306a36Sopenharmony_ci		.cra_priority    = 300,
55062306a36Sopenharmony_ci		.cra_flags       = CRYPTO_ALG_NEED_FALLBACK,
55162306a36Sopenharmony_ci		.cra_blocksize   = 1,
55262306a36Sopenharmony_ci		.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
55362306a36Sopenharmony_ci		.cra_module      = THIS_MODULE,
55462306a36Sopenharmony_ci	},
55562306a36Sopenharmony_ci	.init        = nx_crypto_ctx_aes_ccm_init,
55662306a36Sopenharmony_ci	.exit        = nx_crypto_ctx_aead_exit,
55762306a36Sopenharmony_ci	.ivsize      = 8,
55862306a36Sopenharmony_ci	.maxauthsize = AES_BLOCK_SIZE,
55962306a36Sopenharmony_ci	.setkey      = ccm4309_aes_nx_set_key,
56062306a36Sopenharmony_ci	.setauthsize = ccm4309_aes_nx_setauthsize,
56162306a36Sopenharmony_ci	.encrypt     = ccm4309_aes_nx_encrypt,
56262306a36Sopenharmony_ci	.decrypt     = ccm4309_aes_nx_decrypt,
56362306a36Sopenharmony_ci};
564