162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * AMCC SoC PPC4xx Crypto Driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2008 Applied Micro Circuits Corporation.
662306a36Sopenharmony_ci * All rights reserved. James Hsiao <jhsiao@amcc.com>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * This file implements the Linux crypto algorithms.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/interrupt.h>
1362306a36Sopenharmony_ci#include <linux/spinlock_types.h>
1462306a36Sopenharmony_ci#include <linux/scatterlist.h>
1562306a36Sopenharmony_ci#include <linux/crypto.h>
1662306a36Sopenharmony_ci#include <linux/hash.h>
1762306a36Sopenharmony_ci#include <crypto/internal/hash.h>
1862306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1962306a36Sopenharmony_ci#include <crypto/algapi.h>
2062306a36Sopenharmony_ci#include <crypto/aead.h>
2162306a36Sopenharmony_ci#include <crypto/aes.h>
2262306a36Sopenharmony_ci#include <crypto/gcm.h>
2362306a36Sopenharmony_ci#include <crypto/sha1.h>
2462306a36Sopenharmony_ci#include <crypto/ctr.h>
2562306a36Sopenharmony_ci#include <crypto/skcipher.h>
2662306a36Sopenharmony_ci#include "crypto4xx_reg_def.h"
2762306a36Sopenharmony_ci#include "crypto4xx_core.h"
2862306a36Sopenharmony_ci#include "crypto4xx_sa.h"
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic void set_dynamic_sa_command_0(struct dynamic_sa_ctl *sa, u32 save_h,
3162306a36Sopenharmony_ci				     u32 save_iv, u32 ld_h, u32 ld_iv,
3262306a36Sopenharmony_ci				     u32 hdr_proc, u32 h, u32 c, u32 pad_type,
3362306a36Sopenharmony_ci				     u32 op_grp, u32 op, u32 dir)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	sa->sa_command_0.w = 0;
3662306a36Sopenharmony_ci	sa->sa_command_0.bf.save_hash_state = save_h;
3762306a36Sopenharmony_ci	sa->sa_command_0.bf.save_iv = save_iv;
3862306a36Sopenharmony_ci	sa->sa_command_0.bf.load_hash_state = ld_h;
3962306a36Sopenharmony_ci	sa->sa_command_0.bf.load_iv = ld_iv;
4062306a36Sopenharmony_ci	sa->sa_command_0.bf.hdr_proc = hdr_proc;
4162306a36Sopenharmony_ci	sa->sa_command_0.bf.hash_alg = h;
4262306a36Sopenharmony_ci	sa->sa_command_0.bf.cipher_alg = c;
4362306a36Sopenharmony_ci	sa->sa_command_0.bf.pad_type = pad_type & 3;
4462306a36Sopenharmony_ci	sa->sa_command_0.bf.extend_pad = pad_type >> 2;
4562306a36Sopenharmony_ci	sa->sa_command_0.bf.op_group = op_grp;
4662306a36Sopenharmony_ci	sa->sa_command_0.bf.opcode = op;
4762306a36Sopenharmony_ci	sa->sa_command_0.bf.dir = dir;
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic void set_dynamic_sa_command_1(struct dynamic_sa_ctl *sa, u32 cm,
5162306a36Sopenharmony_ci				     u32 hmac_mc, u32 cfb, u32 esn,
5262306a36Sopenharmony_ci				     u32 sn_mask, u32 mute, u32 cp_pad,
5362306a36Sopenharmony_ci				     u32 cp_pay, u32 cp_hdr)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	sa->sa_command_1.w = 0;
5662306a36Sopenharmony_ci	sa->sa_command_1.bf.crypto_mode31 = (cm & 4) >> 2;
5762306a36Sopenharmony_ci	sa->sa_command_1.bf.crypto_mode9_8 = cm & 3;
5862306a36Sopenharmony_ci	sa->sa_command_1.bf.feedback_mode = cfb;
5962306a36Sopenharmony_ci	sa->sa_command_1.bf.sa_rev = 1;
6062306a36Sopenharmony_ci	sa->sa_command_1.bf.hmac_muting = hmac_mc;
6162306a36Sopenharmony_ci	sa->sa_command_1.bf.extended_seq_num = esn;
6262306a36Sopenharmony_ci	sa->sa_command_1.bf.seq_num_mask = sn_mask;
6362306a36Sopenharmony_ci	sa->sa_command_1.bf.mutable_bit_proc = mute;
6462306a36Sopenharmony_ci	sa->sa_command_1.bf.copy_pad = cp_pad;
6562306a36Sopenharmony_ci	sa->sa_command_1.bf.copy_payload = cp_pay;
6662306a36Sopenharmony_ci	sa->sa_command_1.bf.copy_hdr = cp_hdr;
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic inline int crypto4xx_crypt(struct skcipher_request *req,
7062306a36Sopenharmony_ci				  const unsigned int ivlen, bool decrypt,
7162306a36Sopenharmony_ci				  bool check_blocksize)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(req);
7462306a36Sopenharmony_ci	struct crypto4xx_ctx *ctx = crypto_skcipher_ctx(cipher);
7562306a36Sopenharmony_ci	__le32 iv[AES_IV_SIZE];
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	if (check_blocksize && !IS_ALIGNED(req->cryptlen, AES_BLOCK_SIZE))
7862306a36Sopenharmony_ci		return -EINVAL;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	if (ivlen)
8162306a36Sopenharmony_ci		crypto4xx_memcpy_to_le32(iv, req->iv, ivlen);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
8462306a36Sopenharmony_ci		req->cryptlen, iv, ivlen, decrypt ? ctx->sa_in : ctx->sa_out,
8562306a36Sopenharmony_ci		ctx->sa_len, 0, NULL);
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ciint crypto4xx_encrypt_noiv_block(struct skcipher_request *req)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	return crypto4xx_crypt(req, 0, false, true);
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ciint crypto4xx_encrypt_iv_stream(struct skcipher_request *req)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	return crypto4xx_crypt(req, AES_IV_SIZE, false, false);
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ciint crypto4xx_decrypt_noiv_block(struct skcipher_request *req)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	return crypto4xx_crypt(req, 0, true, true);
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ciint crypto4xx_decrypt_iv_stream(struct skcipher_request *req)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	return crypto4xx_crypt(req, AES_IV_SIZE, true, false);
10662306a36Sopenharmony_ci}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ciint crypto4xx_encrypt_iv_block(struct skcipher_request *req)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	return crypto4xx_crypt(req, AES_IV_SIZE, false, true);
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ciint crypto4xx_decrypt_iv_block(struct skcipher_request *req)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	return crypto4xx_crypt(req, AES_IV_SIZE, true, true);
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci/*
11962306a36Sopenharmony_ci * AES Functions
12062306a36Sopenharmony_ci */
12162306a36Sopenharmony_cistatic int crypto4xx_setkey_aes(struct crypto_skcipher *cipher,
12262306a36Sopenharmony_ci				const u8 *key,
12362306a36Sopenharmony_ci				unsigned int keylen,
12462306a36Sopenharmony_ci				unsigned char cm,
12562306a36Sopenharmony_ci				u8 fb)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	struct crypto4xx_ctx *ctx = crypto_skcipher_ctx(cipher);
12862306a36Sopenharmony_ci	struct dynamic_sa_ctl *sa;
12962306a36Sopenharmony_ci	int    rc;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	if (keylen != AES_KEYSIZE_256 && keylen != AES_KEYSIZE_192 &&
13262306a36Sopenharmony_ci	    keylen != AES_KEYSIZE_128)
13362306a36Sopenharmony_ci		return -EINVAL;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	/* Create SA */
13662306a36Sopenharmony_ci	if (ctx->sa_in || ctx->sa_out)
13762306a36Sopenharmony_ci		crypto4xx_free_sa(ctx);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	rc = crypto4xx_alloc_sa(ctx, SA_AES128_LEN + (keylen-16) / 4);
14062306a36Sopenharmony_ci	if (rc)
14162306a36Sopenharmony_ci		return rc;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	/* Setup SA */
14462306a36Sopenharmony_ci	sa = ctx->sa_in;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	set_dynamic_sa_command_0(sa, SA_NOT_SAVE_HASH, (cm == CRYPTO_MODE_ECB ?
14762306a36Sopenharmony_ci				 SA_NOT_SAVE_IV : SA_SAVE_IV),
14862306a36Sopenharmony_ci				 SA_NOT_LOAD_HASH, (cm == CRYPTO_MODE_ECB ?
14962306a36Sopenharmony_ci				 SA_LOAD_IV_FROM_SA : SA_LOAD_IV_FROM_STATE),
15062306a36Sopenharmony_ci				 SA_NO_HEADER_PROC, SA_HASH_ALG_NULL,
15162306a36Sopenharmony_ci				 SA_CIPHER_ALG_AES, SA_PAD_TYPE_ZERO,
15262306a36Sopenharmony_ci				 SA_OP_GROUP_BASIC, SA_OPCODE_DECRYPT,
15362306a36Sopenharmony_ci				 DIR_INBOUND);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	set_dynamic_sa_command_1(sa, cm, SA_HASH_MODE_HASH,
15662306a36Sopenharmony_ci				 fb, SA_EXTENDED_SN_OFF,
15762306a36Sopenharmony_ci				 SA_SEQ_MASK_OFF, SA_MC_ENABLE,
15862306a36Sopenharmony_ci				 SA_NOT_COPY_PAD, SA_NOT_COPY_PAYLOAD,
15962306a36Sopenharmony_ci				 SA_NOT_COPY_HDR);
16062306a36Sopenharmony_ci	crypto4xx_memcpy_to_le32(get_dynamic_sa_key_field(sa),
16162306a36Sopenharmony_ci				 key, keylen);
16262306a36Sopenharmony_ci	sa->sa_contents.w = SA_AES_CONTENTS | (keylen << 2);
16362306a36Sopenharmony_ci	sa->sa_command_1.bf.key_len = keylen >> 3;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	memcpy(ctx->sa_out, ctx->sa_in, ctx->sa_len * 4);
16662306a36Sopenharmony_ci	sa = ctx->sa_out;
16762306a36Sopenharmony_ci	sa->sa_command_0.bf.dir = DIR_OUTBOUND;
16862306a36Sopenharmony_ci	/*
16962306a36Sopenharmony_ci	 * SA_OPCODE_ENCRYPT is the same value as SA_OPCODE_DECRYPT.
17062306a36Sopenharmony_ci	 * it's the DIR_(IN|OUT)BOUND that matters
17162306a36Sopenharmony_ci	 */
17262306a36Sopenharmony_ci	sa->sa_command_0.bf.opcode = SA_OPCODE_ENCRYPT;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	return 0;
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ciint crypto4xx_setkey_aes_cbc(struct crypto_skcipher *cipher,
17862306a36Sopenharmony_ci			     const u8 *key, unsigned int keylen)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	return crypto4xx_setkey_aes(cipher, key, keylen, CRYPTO_MODE_CBC,
18162306a36Sopenharmony_ci				    CRYPTO_FEEDBACK_MODE_NO_FB);
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ciint crypto4xx_setkey_aes_cfb(struct crypto_skcipher *cipher,
18562306a36Sopenharmony_ci			     const u8 *key, unsigned int keylen)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	return crypto4xx_setkey_aes(cipher, key, keylen, CRYPTO_MODE_CFB,
18862306a36Sopenharmony_ci				    CRYPTO_FEEDBACK_MODE_128BIT_CFB);
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ciint crypto4xx_setkey_aes_ecb(struct crypto_skcipher *cipher,
19262306a36Sopenharmony_ci			     const u8 *key, unsigned int keylen)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	return crypto4xx_setkey_aes(cipher, key, keylen, CRYPTO_MODE_ECB,
19562306a36Sopenharmony_ci				    CRYPTO_FEEDBACK_MODE_NO_FB);
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ciint crypto4xx_setkey_aes_ofb(struct crypto_skcipher *cipher,
19962306a36Sopenharmony_ci			     const u8 *key, unsigned int keylen)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	return crypto4xx_setkey_aes(cipher, key, keylen, CRYPTO_MODE_OFB,
20262306a36Sopenharmony_ci				    CRYPTO_FEEDBACK_MODE_64BIT_OFB);
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ciint crypto4xx_setkey_rfc3686(struct crypto_skcipher *cipher,
20662306a36Sopenharmony_ci			     const u8 *key, unsigned int keylen)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	struct crypto4xx_ctx *ctx = crypto_skcipher_ctx(cipher);
20962306a36Sopenharmony_ci	int rc;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	rc = crypto4xx_setkey_aes(cipher, key, keylen - CTR_RFC3686_NONCE_SIZE,
21262306a36Sopenharmony_ci		CRYPTO_MODE_CTR, CRYPTO_FEEDBACK_MODE_NO_FB);
21362306a36Sopenharmony_ci	if (rc)
21462306a36Sopenharmony_ci		return rc;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	ctx->iv_nonce = cpu_to_le32p((u32 *)&key[keylen -
21762306a36Sopenharmony_ci						 CTR_RFC3686_NONCE_SIZE]);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	return 0;
22062306a36Sopenharmony_ci}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ciint crypto4xx_rfc3686_encrypt(struct skcipher_request *req)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(req);
22562306a36Sopenharmony_ci	struct crypto4xx_ctx *ctx = crypto_skcipher_ctx(cipher);
22662306a36Sopenharmony_ci	__le32 iv[AES_IV_SIZE / 4] = {
22762306a36Sopenharmony_ci		ctx->iv_nonce,
22862306a36Sopenharmony_ci		cpu_to_le32p((u32 *) req->iv),
22962306a36Sopenharmony_ci		cpu_to_le32p((u32 *) (req->iv + 4)),
23062306a36Sopenharmony_ci		cpu_to_le32(1) };
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
23362306a36Sopenharmony_ci				  req->cryptlen, iv, AES_IV_SIZE,
23462306a36Sopenharmony_ci				  ctx->sa_out, ctx->sa_len, 0, NULL);
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ciint crypto4xx_rfc3686_decrypt(struct skcipher_request *req)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(req);
24062306a36Sopenharmony_ci	struct crypto4xx_ctx *ctx = crypto_skcipher_ctx(cipher);
24162306a36Sopenharmony_ci	__le32 iv[AES_IV_SIZE / 4] = {
24262306a36Sopenharmony_ci		ctx->iv_nonce,
24362306a36Sopenharmony_ci		cpu_to_le32p((u32 *) req->iv),
24462306a36Sopenharmony_ci		cpu_to_le32p((u32 *) (req->iv + 4)),
24562306a36Sopenharmony_ci		cpu_to_le32(1) };
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
24862306a36Sopenharmony_ci				  req->cryptlen, iv, AES_IV_SIZE,
24962306a36Sopenharmony_ci				  ctx->sa_out, ctx->sa_len, 0, NULL);
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic int
25362306a36Sopenharmony_cicrypto4xx_ctr_crypt(struct skcipher_request *req, bool encrypt)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(req);
25662306a36Sopenharmony_ci	struct crypto4xx_ctx *ctx = crypto_skcipher_ctx(cipher);
25762306a36Sopenharmony_ci	size_t iv_len = crypto_skcipher_ivsize(cipher);
25862306a36Sopenharmony_ci	unsigned int counter = be32_to_cpup((__be32 *)(req->iv + iv_len - 4));
25962306a36Sopenharmony_ci	unsigned int nblks = ALIGN(req->cryptlen, AES_BLOCK_SIZE) /
26062306a36Sopenharmony_ci			AES_BLOCK_SIZE;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	/*
26362306a36Sopenharmony_ci	 * The hardware uses only the last 32-bits as the counter while the
26462306a36Sopenharmony_ci	 * kernel tests (aes_ctr_enc_tv_template[4] for example) expect that
26562306a36Sopenharmony_ci	 * the whole IV is a counter.  So fallback if the counter is going to
26662306a36Sopenharmony_ci	 * overlow.
26762306a36Sopenharmony_ci	 */
26862306a36Sopenharmony_ci	if (counter + nblks < counter) {
26962306a36Sopenharmony_ci		SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->sw_cipher.cipher);
27062306a36Sopenharmony_ci		int ret;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci		skcipher_request_set_sync_tfm(subreq, ctx->sw_cipher.cipher);
27362306a36Sopenharmony_ci		skcipher_request_set_callback(subreq, req->base.flags,
27462306a36Sopenharmony_ci			NULL, NULL);
27562306a36Sopenharmony_ci		skcipher_request_set_crypt(subreq, req->src, req->dst,
27662306a36Sopenharmony_ci			req->cryptlen, req->iv);
27762306a36Sopenharmony_ci		ret = encrypt ? crypto_skcipher_encrypt(subreq)
27862306a36Sopenharmony_ci			: crypto_skcipher_decrypt(subreq);
27962306a36Sopenharmony_ci		skcipher_request_zero(subreq);
28062306a36Sopenharmony_ci		return ret;
28162306a36Sopenharmony_ci	}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	return encrypt ? crypto4xx_encrypt_iv_stream(req)
28462306a36Sopenharmony_ci		       : crypto4xx_decrypt_iv_stream(req);
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_cistatic int crypto4xx_sk_setup_fallback(struct crypto4xx_ctx *ctx,
28862306a36Sopenharmony_ci				       struct crypto_skcipher *cipher,
28962306a36Sopenharmony_ci				       const u8 *key,
29062306a36Sopenharmony_ci				       unsigned int keylen)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	crypto_sync_skcipher_clear_flags(ctx->sw_cipher.cipher,
29362306a36Sopenharmony_ci				    CRYPTO_TFM_REQ_MASK);
29462306a36Sopenharmony_ci	crypto_sync_skcipher_set_flags(ctx->sw_cipher.cipher,
29562306a36Sopenharmony_ci		crypto_skcipher_get_flags(cipher) & CRYPTO_TFM_REQ_MASK);
29662306a36Sopenharmony_ci	return crypto_sync_skcipher_setkey(ctx->sw_cipher.cipher, key, keylen);
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ciint crypto4xx_setkey_aes_ctr(struct crypto_skcipher *cipher,
30062306a36Sopenharmony_ci			     const u8 *key, unsigned int keylen)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	struct crypto4xx_ctx *ctx = crypto_skcipher_ctx(cipher);
30362306a36Sopenharmony_ci	int rc;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	rc = crypto4xx_sk_setup_fallback(ctx, cipher, key, keylen);
30662306a36Sopenharmony_ci	if (rc)
30762306a36Sopenharmony_ci		return rc;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	return crypto4xx_setkey_aes(cipher, key, keylen,
31062306a36Sopenharmony_ci		CRYPTO_MODE_CTR, CRYPTO_FEEDBACK_MODE_NO_FB);
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ciint crypto4xx_encrypt_ctr(struct skcipher_request *req)
31462306a36Sopenharmony_ci{
31562306a36Sopenharmony_ci	return crypto4xx_ctr_crypt(req, true);
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ciint crypto4xx_decrypt_ctr(struct skcipher_request *req)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	return crypto4xx_ctr_crypt(req, false);
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic inline bool crypto4xx_aead_need_fallback(struct aead_request *req,
32462306a36Sopenharmony_ci						unsigned int len,
32562306a36Sopenharmony_ci						bool is_ccm, bool decrypt)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	struct crypto_aead *aead = crypto_aead_reqtfm(req);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	/* authsize has to be a multiple of 4 */
33062306a36Sopenharmony_ci	if (aead->authsize & 3)
33162306a36Sopenharmony_ci		return true;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	/*
33462306a36Sopenharmony_ci	 * hardware does not handle cases where plaintext
33562306a36Sopenharmony_ci	 * is less than a block.
33662306a36Sopenharmony_ci	 */
33762306a36Sopenharmony_ci	if (len < AES_BLOCK_SIZE)
33862306a36Sopenharmony_ci		return true;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	/* assoc len needs to be a multiple of 4 and <= 1020 */
34162306a36Sopenharmony_ci	if (req->assoclen & 0x3 || req->assoclen > 1020)
34262306a36Sopenharmony_ci		return true;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	/* CCM supports only counter field length of 2 and 4 bytes */
34562306a36Sopenharmony_ci	if (is_ccm && !(req->iv[0] == 1 || req->iv[0] == 3))
34662306a36Sopenharmony_ci		return true;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	return false;
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_cistatic int crypto4xx_aead_fallback(struct aead_request *req,
35262306a36Sopenharmony_ci	struct crypto4xx_ctx *ctx, bool do_decrypt)
35362306a36Sopenharmony_ci{
35462306a36Sopenharmony_ci	struct aead_request *subreq = aead_request_ctx(req);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	aead_request_set_tfm(subreq, ctx->sw_cipher.aead);
35762306a36Sopenharmony_ci	aead_request_set_callback(subreq, req->base.flags,
35862306a36Sopenharmony_ci				  req->base.complete, req->base.data);
35962306a36Sopenharmony_ci	aead_request_set_crypt(subreq, req->src, req->dst, req->cryptlen,
36062306a36Sopenharmony_ci			       req->iv);
36162306a36Sopenharmony_ci	aead_request_set_ad(subreq, req->assoclen);
36262306a36Sopenharmony_ci	return do_decrypt ? crypto_aead_decrypt(subreq) :
36362306a36Sopenharmony_ci			    crypto_aead_encrypt(subreq);
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic int crypto4xx_aead_setup_fallback(struct crypto4xx_ctx *ctx,
36762306a36Sopenharmony_ci					 struct crypto_aead *cipher,
36862306a36Sopenharmony_ci					 const u8 *key,
36962306a36Sopenharmony_ci					 unsigned int keylen)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci	crypto_aead_clear_flags(ctx->sw_cipher.aead, CRYPTO_TFM_REQ_MASK);
37262306a36Sopenharmony_ci	crypto_aead_set_flags(ctx->sw_cipher.aead,
37362306a36Sopenharmony_ci		crypto_aead_get_flags(cipher) & CRYPTO_TFM_REQ_MASK);
37462306a36Sopenharmony_ci	return crypto_aead_setkey(ctx->sw_cipher.aead, key, keylen);
37562306a36Sopenharmony_ci}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci/*
37862306a36Sopenharmony_ci * AES-CCM Functions
37962306a36Sopenharmony_ci */
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ciint crypto4xx_setkey_aes_ccm(struct crypto_aead *cipher, const u8 *key,
38262306a36Sopenharmony_ci			     unsigned int keylen)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	struct crypto_tfm *tfm = crypto_aead_tfm(cipher);
38562306a36Sopenharmony_ci	struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm);
38662306a36Sopenharmony_ci	struct dynamic_sa_ctl *sa;
38762306a36Sopenharmony_ci	int rc = 0;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	rc = crypto4xx_aead_setup_fallback(ctx, cipher, key, keylen);
39062306a36Sopenharmony_ci	if (rc)
39162306a36Sopenharmony_ci		return rc;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	if (ctx->sa_in || ctx->sa_out)
39462306a36Sopenharmony_ci		crypto4xx_free_sa(ctx);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	rc = crypto4xx_alloc_sa(ctx, SA_AES128_CCM_LEN + (keylen - 16) / 4);
39762306a36Sopenharmony_ci	if (rc)
39862306a36Sopenharmony_ci		return rc;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	/* Setup SA */
40162306a36Sopenharmony_ci	sa = (struct dynamic_sa_ctl *) ctx->sa_in;
40262306a36Sopenharmony_ci	sa->sa_contents.w = SA_AES_CCM_CONTENTS | (keylen << 2);
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	set_dynamic_sa_command_0(sa, SA_SAVE_HASH, SA_NOT_SAVE_IV,
40562306a36Sopenharmony_ci				 SA_LOAD_HASH_FROM_SA, SA_LOAD_IV_FROM_STATE,
40662306a36Sopenharmony_ci				 SA_NO_HEADER_PROC, SA_HASH_ALG_CBC_MAC,
40762306a36Sopenharmony_ci				 SA_CIPHER_ALG_AES,
40862306a36Sopenharmony_ci				 SA_PAD_TYPE_ZERO, SA_OP_GROUP_BASIC,
40962306a36Sopenharmony_ci				 SA_OPCODE_HASH_DECRYPT, DIR_INBOUND);
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	set_dynamic_sa_command_1(sa, CRYPTO_MODE_CTR, SA_HASH_MODE_HASH,
41262306a36Sopenharmony_ci				 CRYPTO_FEEDBACK_MODE_NO_FB, SA_EXTENDED_SN_OFF,
41362306a36Sopenharmony_ci				 SA_SEQ_MASK_OFF, SA_MC_ENABLE,
41462306a36Sopenharmony_ci				 SA_NOT_COPY_PAD, SA_COPY_PAYLOAD,
41562306a36Sopenharmony_ci				 SA_NOT_COPY_HDR);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	sa->sa_command_1.bf.key_len = keylen >> 3;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	crypto4xx_memcpy_to_le32(get_dynamic_sa_key_field(sa), key, keylen);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	memcpy(ctx->sa_out, ctx->sa_in, ctx->sa_len * 4);
42262306a36Sopenharmony_ci	sa = (struct dynamic_sa_ctl *) ctx->sa_out;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	set_dynamic_sa_command_0(sa, SA_SAVE_HASH, SA_NOT_SAVE_IV,
42562306a36Sopenharmony_ci				 SA_LOAD_HASH_FROM_SA, SA_LOAD_IV_FROM_STATE,
42662306a36Sopenharmony_ci				 SA_NO_HEADER_PROC, SA_HASH_ALG_CBC_MAC,
42762306a36Sopenharmony_ci				 SA_CIPHER_ALG_AES,
42862306a36Sopenharmony_ci				 SA_PAD_TYPE_ZERO, SA_OP_GROUP_BASIC,
42962306a36Sopenharmony_ci				 SA_OPCODE_ENCRYPT_HASH, DIR_OUTBOUND);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	set_dynamic_sa_command_1(sa, CRYPTO_MODE_CTR, SA_HASH_MODE_HASH,
43262306a36Sopenharmony_ci				 CRYPTO_FEEDBACK_MODE_NO_FB, SA_EXTENDED_SN_OFF,
43362306a36Sopenharmony_ci				 SA_SEQ_MASK_OFF, SA_MC_ENABLE,
43462306a36Sopenharmony_ci				 SA_COPY_PAD, SA_COPY_PAYLOAD,
43562306a36Sopenharmony_ci				 SA_NOT_COPY_HDR);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	sa->sa_command_1.bf.key_len = keylen >> 3;
43862306a36Sopenharmony_ci	return 0;
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_cistatic int crypto4xx_crypt_aes_ccm(struct aead_request *req, bool decrypt)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	struct crypto4xx_ctx *ctx  = crypto_tfm_ctx(req->base.tfm);
44462306a36Sopenharmony_ci	struct crypto4xx_aead_reqctx *rctx = aead_request_ctx(req);
44562306a36Sopenharmony_ci	struct crypto_aead *aead = crypto_aead_reqtfm(req);
44662306a36Sopenharmony_ci	__le32 iv[16];
44762306a36Sopenharmony_ci	u32 tmp_sa[SA_AES128_CCM_LEN + 4];
44862306a36Sopenharmony_ci	struct dynamic_sa_ctl *sa = (struct dynamic_sa_ctl *)tmp_sa;
44962306a36Sopenharmony_ci	unsigned int len = req->cryptlen;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	if (decrypt)
45262306a36Sopenharmony_ci		len -= crypto_aead_authsize(aead);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	if (crypto4xx_aead_need_fallback(req, len, true, decrypt))
45562306a36Sopenharmony_ci		return crypto4xx_aead_fallback(req, ctx, decrypt);
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	memcpy(tmp_sa, decrypt ? ctx->sa_in : ctx->sa_out, ctx->sa_len * 4);
45862306a36Sopenharmony_ci	sa->sa_command_0.bf.digest_len = crypto_aead_authsize(aead) >> 2;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	if (req->iv[0] == 1) {
46162306a36Sopenharmony_ci		/* CRYPTO_MODE_AES_ICM */
46262306a36Sopenharmony_ci		sa->sa_command_1.bf.crypto_mode9_8 = 1;
46362306a36Sopenharmony_ci	}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	iv[3] = cpu_to_le32(0);
46662306a36Sopenharmony_ci	crypto4xx_memcpy_to_le32(iv, req->iv, 16 - (req->iv[0] + 1));
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
46962306a36Sopenharmony_ci				  len, iv, sizeof(iv),
47062306a36Sopenharmony_ci				  sa, ctx->sa_len, req->assoclen, rctx->dst);
47162306a36Sopenharmony_ci}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ciint crypto4xx_encrypt_aes_ccm(struct aead_request *req)
47462306a36Sopenharmony_ci{
47562306a36Sopenharmony_ci	return crypto4xx_crypt_aes_ccm(req, false);
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ciint crypto4xx_decrypt_aes_ccm(struct aead_request *req)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci	return crypto4xx_crypt_aes_ccm(req, true);
48162306a36Sopenharmony_ci}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ciint crypto4xx_setauthsize_aead(struct crypto_aead *cipher,
48462306a36Sopenharmony_ci			       unsigned int authsize)
48562306a36Sopenharmony_ci{
48662306a36Sopenharmony_ci	struct crypto_tfm *tfm = crypto_aead_tfm(cipher);
48762306a36Sopenharmony_ci	struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm);
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	return crypto_aead_setauthsize(ctx->sw_cipher.aead, authsize);
49062306a36Sopenharmony_ci}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci/*
49362306a36Sopenharmony_ci * AES-GCM Functions
49462306a36Sopenharmony_ci */
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_cistatic int crypto4xx_aes_gcm_validate_keylen(unsigned int keylen)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	switch (keylen) {
49962306a36Sopenharmony_ci	case 16:
50062306a36Sopenharmony_ci	case 24:
50162306a36Sopenharmony_ci	case 32:
50262306a36Sopenharmony_ci		return 0;
50362306a36Sopenharmony_ci	default:
50462306a36Sopenharmony_ci		return -EINVAL;
50562306a36Sopenharmony_ci	}
50662306a36Sopenharmony_ci}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_cistatic int crypto4xx_compute_gcm_hash_key_sw(__le32 *hash_start, const u8 *key,
50962306a36Sopenharmony_ci					     unsigned int keylen)
51062306a36Sopenharmony_ci{
51162306a36Sopenharmony_ci	struct crypto_aes_ctx ctx;
51262306a36Sopenharmony_ci	uint8_t src[16] = { 0 };
51362306a36Sopenharmony_ci	int rc;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	rc = aes_expandkey(&ctx, key, keylen);
51662306a36Sopenharmony_ci	if (rc) {
51762306a36Sopenharmony_ci		pr_err("aes_expandkey() failed: %d\n", rc);
51862306a36Sopenharmony_ci		return rc;
51962306a36Sopenharmony_ci	}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	aes_encrypt(&ctx, src, src);
52262306a36Sopenharmony_ci	crypto4xx_memcpy_to_le32(hash_start, src, 16);
52362306a36Sopenharmony_ci	memzero_explicit(&ctx, sizeof(ctx));
52462306a36Sopenharmony_ci	return 0;
52562306a36Sopenharmony_ci}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ciint crypto4xx_setkey_aes_gcm(struct crypto_aead *cipher,
52862306a36Sopenharmony_ci			     const u8 *key, unsigned int keylen)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	struct crypto_tfm *tfm = crypto_aead_tfm(cipher);
53162306a36Sopenharmony_ci	struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm);
53262306a36Sopenharmony_ci	struct dynamic_sa_ctl *sa;
53362306a36Sopenharmony_ci	int    rc = 0;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	if (crypto4xx_aes_gcm_validate_keylen(keylen) != 0)
53662306a36Sopenharmony_ci		return -EINVAL;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	rc = crypto4xx_aead_setup_fallback(ctx, cipher, key, keylen);
53962306a36Sopenharmony_ci	if (rc)
54062306a36Sopenharmony_ci		return rc;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	if (ctx->sa_in || ctx->sa_out)
54362306a36Sopenharmony_ci		crypto4xx_free_sa(ctx);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	rc = crypto4xx_alloc_sa(ctx, SA_AES128_GCM_LEN + (keylen - 16) / 4);
54662306a36Sopenharmony_ci	if (rc)
54762306a36Sopenharmony_ci		return rc;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	sa  = (struct dynamic_sa_ctl *) ctx->sa_in;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	sa->sa_contents.w = SA_AES_GCM_CONTENTS | (keylen << 2);
55262306a36Sopenharmony_ci	set_dynamic_sa_command_0(sa, SA_SAVE_HASH, SA_NOT_SAVE_IV,
55362306a36Sopenharmony_ci				 SA_LOAD_HASH_FROM_SA, SA_LOAD_IV_FROM_STATE,
55462306a36Sopenharmony_ci				 SA_NO_HEADER_PROC, SA_HASH_ALG_GHASH,
55562306a36Sopenharmony_ci				 SA_CIPHER_ALG_AES, SA_PAD_TYPE_ZERO,
55662306a36Sopenharmony_ci				 SA_OP_GROUP_BASIC, SA_OPCODE_HASH_DECRYPT,
55762306a36Sopenharmony_ci				 DIR_INBOUND);
55862306a36Sopenharmony_ci	set_dynamic_sa_command_1(sa, CRYPTO_MODE_CTR, SA_HASH_MODE_HASH,
55962306a36Sopenharmony_ci				 CRYPTO_FEEDBACK_MODE_NO_FB, SA_EXTENDED_SN_OFF,
56062306a36Sopenharmony_ci				 SA_SEQ_MASK_ON, SA_MC_DISABLE,
56162306a36Sopenharmony_ci				 SA_NOT_COPY_PAD, SA_COPY_PAYLOAD,
56262306a36Sopenharmony_ci				 SA_NOT_COPY_HDR);
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	sa->sa_command_1.bf.key_len = keylen >> 3;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	crypto4xx_memcpy_to_le32(get_dynamic_sa_key_field(sa),
56762306a36Sopenharmony_ci				 key, keylen);
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	rc = crypto4xx_compute_gcm_hash_key_sw(get_dynamic_sa_inner_digest(sa),
57062306a36Sopenharmony_ci		key, keylen);
57162306a36Sopenharmony_ci	if (rc) {
57262306a36Sopenharmony_ci		pr_err("GCM hash key setting failed = %d\n", rc);
57362306a36Sopenharmony_ci		goto err;
57462306a36Sopenharmony_ci	}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	memcpy(ctx->sa_out, ctx->sa_in, ctx->sa_len * 4);
57762306a36Sopenharmony_ci	sa = (struct dynamic_sa_ctl *) ctx->sa_out;
57862306a36Sopenharmony_ci	sa->sa_command_0.bf.dir = DIR_OUTBOUND;
57962306a36Sopenharmony_ci	sa->sa_command_0.bf.opcode = SA_OPCODE_ENCRYPT_HASH;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	return 0;
58262306a36Sopenharmony_cierr:
58362306a36Sopenharmony_ci	crypto4xx_free_sa(ctx);
58462306a36Sopenharmony_ci	return rc;
58562306a36Sopenharmony_ci}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_cistatic inline int crypto4xx_crypt_aes_gcm(struct aead_request *req,
58862306a36Sopenharmony_ci					  bool decrypt)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
59162306a36Sopenharmony_ci	struct crypto4xx_aead_reqctx *rctx = aead_request_ctx(req);
59262306a36Sopenharmony_ci	__le32 iv[4];
59362306a36Sopenharmony_ci	unsigned int len = req->cryptlen;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	if (decrypt)
59662306a36Sopenharmony_ci		len -= crypto_aead_authsize(crypto_aead_reqtfm(req));
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	if (crypto4xx_aead_need_fallback(req, len, false, decrypt))
59962306a36Sopenharmony_ci		return crypto4xx_aead_fallback(req, ctx, decrypt);
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	crypto4xx_memcpy_to_le32(iv, req->iv, GCM_AES_IV_SIZE);
60262306a36Sopenharmony_ci	iv[3] = cpu_to_le32(1);
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
60562306a36Sopenharmony_ci				  len, iv, sizeof(iv),
60662306a36Sopenharmony_ci				  decrypt ? ctx->sa_in : ctx->sa_out,
60762306a36Sopenharmony_ci				  ctx->sa_len, req->assoclen, rctx->dst);
60862306a36Sopenharmony_ci}
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ciint crypto4xx_encrypt_aes_gcm(struct aead_request *req)
61162306a36Sopenharmony_ci{
61262306a36Sopenharmony_ci	return crypto4xx_crypt_aes_gcm(req, false);
61362306a36Sopenharmony_ci}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ciint crypto4xx_decrypt_aes_gcm(struct aead_request *req)
61662306a36Sopenharmony_ci{
61762306a36Sopenharmony_ci	return crypto4xx_crypt_aes_gcm(req, true);
61862306a36Sopenharmony_ci}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci/*
62162306a36Sopenharmony_ci * HASH SHA1 Functions
62262306a36Sopenharmony_ci */
62362306a36Sopenharmony_cistatic int crypto4xx_hash_alg_init(struct crypto_tfm *tfm,
62462306a36Sopenharmony_ci				   unsigned int sa_len,
62562306a36Sopenharmony_ci				   unsigned char ha,
62662306a36Sopenharmony_ci				   unsigned char hm)
62762306a36Sopenharmony_ci{
62862306a36Sopenharmony_ci	struct crypto_alg *alg = tfm->__crt_alg;
62962306a36Sopenharmony_ci	struct crypto4xx_alg *my_alg;
63062306a36Sopenharmony_ci	struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm);
63162306a36Sopenharmony_ci	struct dynamic_sa_hash160 *sa;
63262306a36Sopenharmony_ci	int rc;
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	my_alg = container_of(__crypto_ahash_alg(alg), struct crypto4xx_alg,
63562306a36Sopenharmony_ci			      alg.u.hash);
63662306a36Sopenharmony_ci	ctx->dev   = my_alg->dev;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	/* Create SA */
63962306a36Sopenharmony_ci	if (ctx->sa_in || ctx->sa_out)
64062306a36Sopenharmony_ci		crypto4xx_free_sa(ctx);
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	rc = crypto4xx_alloc_sa(ctx, sa_len);
64362306a36Sopenharmony_ci	if (rc)
64462306a36Sopenharmony_ci		return rc;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
64762306a36Sopenharmony_ci				 sizeof(struct crypto4xx_ctx));
64862306a36Sopenharmony_ci	sa = (struct dynamic_sa_hash160 *)ctx->sa_in;
64962306a36Sopenharmony_ci	set_dynamic_sa_command_0(&sa->ctrl, SA_SAVE_HASH, SA_NOT_SAVE_IV,
65062306a36Sopenharmony_ci				 SA_NOT_LOAD_HASH, SA_LOAD_IV_FROM_SA,
65162306a36Sopenharmony_ci				 SA_NO_HEADER_PROC, ha, SA_CIPHER_ALG_NULL,
65262306a36Sopenharmony_ci				 SA_PAD_TYPE_ZERO, SA_OP_GROUP_BASIC,
65362306a36Sopenharmony_ci				 SA_OPCODE_HASH, DIR_INBOUND);
65462306a36Sopenharmony_ci	set_dynamic_sa_command_1(&sa->ctrl, 0, SA_HASH_MODE_HASH,
65562306a36Sopenharmony_ci				 CRYPTO_FEEDBACK_MODE_NO_FB, SA_EXTENDED_SN_OFF,
65662306a36Sopenharmony_ci				 SA_SEQ_MASK_OFF, SA_MC_ENABLE,
65762306a36Sopenharmony_ci				 SA_NOT_COPY_PAD, SA_NOT_COPY_PAYLOAD,
65862306a36Sopenharmony_ci				 SA_NOT_COPY_HDR);
65962306a36Sopenharmony_ci	/* Need to zero hash digest in SA */
66062306a36Sopenharmony_ci	memset(sa->inner_digest, 0, sizeof(sa->inner_digest));
66162306a36Sopenharmony_ci	memset(sa->outer_digest, 0, sizeof(sa->outer_digest));
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	return 0;
66462306a36Sopenharmony_ci}
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ciint crypto4xx_hash_init(struct ahash_request *req)
66762306a36Sopenharmony_ci{
66862306a36Sopenharmony_ci	struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
66962306a36Sopenharmony_ci	int ds;
67062306a36Sopenharmony_ci	struct dynamic_sa_ctl *sa;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	sa = ctx->sa_in;
67362306a36Sopenharmony_ci	ds = crypto_ahash_digestsize(
67462306a36Sopenharmony_ci			__crypto_ahash_cast(req->base.tfm));
67562306a36Sopenharmony_ci	sa->sa_command_0.bf.digest_len = ds >> 2;
67662306a36Sopenharmony_ci	sa->sa_command_0.bf.load_hash_state = SA_LOAD_HASH_FROM_SA;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	return 0;
67962306a36Sopenharmony_ci}
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ciint crypto4xx_hash_update(struct ahash_request *req)
68262306a36Sopenharmony_ci{
68362306a36Sopenharmony_ci	struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
68462306a36Sopenharmony_ci	struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
68562306a36Sopenharmony_ci	struct scatterlist dst;
68662306a36Sopenharmony_ci	unsigned int ds = crypto_ahash_digestsize(ahash);
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	sg_init_one(&dst, req->result, ds);
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	return crypto4xx_build_pd(&req->base, ctx, req->src, &dst,
69162306a36Sopenharmony_ci				  req->nbytes, NULL, 0, ctx->sa_in,
69262306a36Sopenharmony_ci				  ctx->sa_len, 0, NULL);
69362306a36Sopenharmony_ci}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ciint crypto4xx_hash_final(struct ahash_request *req)
69662306a36Sopenharmony_ci{
69762306a36Sopenharmony_ci	return 0;
69862306a36Sopenharmony_ci}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ciint crypto4xx_hash_digest(struct ahash_request *req)
70162306a36Sopenharmony_ci{
70262306a36Sopenharmony_ci	struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
70362306a36Sopenharmony_ci	struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
70462306a36Sopenharmony_ci	struct scatterlist dst;
70562306a36Sopenharmony_ci	unsigned int ds = crypto_ahash_digestsize(ahash);
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	sg_init_one(&dst, req->result, ds);
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	return crypto4xx_build_pd(&req->base, ctx, req->src, &dst,
71062306a36Sopenharmony_ci				  req->nbytes, NULL, 0, ctx->sa_in,
71162306a36Sopenharmony_ci				  ctx->sa_len, 0, NULL);
71262306a36Sopenharmony_ci}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci/*
71562306a36Sopenharmony_ci * SHA1 Algorithm
71662306a36Sopenharmony_ci */
71762306a36Sopenharmony_ciint crypto4xx_sha1_alg_init(struct crypto_tfm *tfm)
71862306a36Sopenharmony_ci{
71962306a36Sopenharmony_ci	return crypto4xx_hash_alg_init(tfm, SA_HASH160_LEN, SA_HASH_ALG_SHA1,
72062306a36Sopenharmony_ci				       SA_HASH_MODE_HASH);
72162306a36Sopenharmony_ci}
722