162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * AMD Cryptographic Coprocessor (CCP) driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2013-2019 Advanced Micro Devices, Inc.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author: Tom Lendacky <thomas.lendacky@amd.com>
862306a36Sopenharmony_ci * Author: Gary R Hook <gary.hook@amd.com>
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/interrupt.h>
1562306a36Sopenharmony_ci#include <crypto/scatterwalk.h>
1662306a36Sopenharmony_ci#include <crypto/des.h>
1762306a36Sopenharmony_ci#include <linux/ccp.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "ccp-dev.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/* SHA initial context values */
2262306a36Sopenharmony_cistatic const __be32 ccp_sha1_init[SHA1_DIGEST_SIZE / sizeof(__be32)] = {
2362306a36Sopenharmony_ci	cpu_to_be32(SHA1_H0), cpu_to_be32(SHA1_H1),
2462306a36Sopenharmony_ci	cpu_to_be32(SHA1_H2), cpu_to_be32(SHA1_H3),
2562306a36Sopenharmony_ci	cpu_to_be32(SHA1_H4),
2662306a36Sopenharmony_ci};
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic const __be32 ccp_sha224_init[SHA256_DIGEST_SIZE / sizeof(__be32)] = {
2962306a36Sopenharmony_ci	cpu_to_be32(SHA224_H0), cpu_to_be32(SHA224_H1),
3062306a36Sopenharmony_ci	cpu_to_be32(SHA224_H2), cpu_to_be32(SHA224_H3),
3162306a36Sopenharmony_ci	cpu_to_be32(SHA224_H4), cpu_to_be32(SHA224_H5),
3262306a36Sopenharmony_ci	cpu_to_be32(SHA224_H6), cpu_to_be32(SHA224_H7),
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic const __be32 ccp_sha256_init[SHA256_DIGEST_SIZE / sizeof(__be32)] = {
3662306a36Sopenharmony_ci	cpu_to_be32(SHA256_H0), cpu_to_be32(SHA256_H1),
3762306a36Sopenharmony_ci	cpu_to_be32(SHA256_H2), cpu_to_be32(SHA256_H3),
3862306a36Sopenharmony_ci	cpu_to_be32(SHA256_H4), cpu_to_be32(SHA256_H5),
3962306a36Sopenharmony_ci	cpu_to_be32(SHA256_H6), cpu_to_be32(SHA256_H7),
4062306a36Sopenharmony_ci};
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic const __be64 ccp_sha384_init[SHA512_DIGEST_SIZE / sizeof(__be64)] = {
4362306a36Sopenharmony_ci	cpu_to_be64(SHA384_H0), cpu_to_be64(SHA384_H1),
4462306a36Sopenharmony_ci	cpu_to_be64(SHA384_H2), cpu_to_be64(SHA384_H3),
4562306a36Sopenharmony_ci	cpu_to_be64(SHA384_H4), cpu_to_be64(SHA384_H5),
4662306a36Sopenharmony_ci	cpu_to_be64(SHA384_H6), cpu_to_be64(SHA384_H7),
4762306a36Sopenharmony_ci};
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic const __be64 ccp_sha512_init[SHA512_DIGEST_SIZE / sizeof(__be64)] = {
5062306a36Sopenharmony_ci	cpu_to_be64(SHA512_H0), cpu_to_be64(SHA512_H1),
5162306a36Sopenharmony_ci	cpu_to_be64(SHA512_H2), cpu_to_be64(SHA512_H3),
5262306a36Sopenharmony_ci	cpu_to_be64(SHA512_H4), cpu_to_be64(SHA512_H5),
5362306a36Sopenharmony_ci	cpu_to_be64(SHA512_H6), cpu_to_be64(SHA512_H7),
5462306a36Sopenharmony_ci};
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci#define	CCP_NEW_JOBID(ccp)	((ccp->vdata->version == CCP_VERSION(3, 0)) ? \
5762306a36Sopenharmony_ci					ccp_gen_jobid(ccp) : 0)
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic u32 ccp_gen_jobid(struct ccp_device *ccp)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	return atomic_inc_return(&ccp->current_id) & CCP_JOBID_MASK;
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic void ccp_sg_free(struct ccp_sg_workarea *wa)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	if (wa->dma_count)
6762306a36Sopenharmony_ci		dma_unmap_sg(wa->dma_dev, wa->dma_sg_head, wa->nents, wa->dma_dir);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	wa->dma_count = 0;
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic int ccp_init_sg_workarea(struct ccp_sg_workarea *wa, struct device *dev,
7362306a36Sopenharmony_ci				struct scatterlist *sg, u64 len,
7462306a36Sopenharmony_ci				enum dma_data_direction dma_dir)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	memset(wa, 0, sizeof(*wa));
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	wa->sg = sg;
7962306a36Sopenharmony_ci	if (!sg)
8062306a36Sopenharmony_ci		return 0;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	wa->nents = sg_nents_for_len(sg, len);
8362306a36Sopenharmony_ci	if (wa->nents < 0)
8462306a36Sopenharmony_ci		return wa->nents;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	wa->bytes_left = len;
8762306a36Sopenharmony_ci	wa->sg_used = 0;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	if (len == 0)
9062306a36Sopenharmony_ci		return 0;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	if (dma_dir == DMA_NONE)
9362306a36Sopenharmony_ci		return 0;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	wa->dma_sg = sg;
9662306a36Sopenharmony_ci	wa->dma_sg_head = sg;
9762306a36Sopenharmony_ci	wa->dma_dev = dev;
9862306a36Sopenharmony_ci	wa->dma_dir = dma_dir;
9962306a36Sopenharmony_ci	wa->dma_count = dma_map_sg(dev, sg, wa->nents, dma_dir);
10062306a36Sopenharmony_ci	if (!wa->dma_count)
10162306a36Sopenharmony_ci		return -ENOMEM;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	return 0;
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic void ccp_update_sg_workarea(struct ccp_sg_workarea *wa, unsigned int len)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	unsigned int nbytes = min_t(u64, len, wa->bytes_left);
10962306a36Sopenharmony_ci	unsigned int sg_combined_len = 0;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	if (!wa->sg)
11262306a36Sopenharmony_ci		return;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	wa->sg_used += nbytes;
11562306a36Sopenharmony_ci	wa->bytes_left -= nbytes;
11662306a36Sopenharmony_ci	if (wa->sg_used == sg_dma_len(wa->dma_sg)) {
11762306a36Sopenharmony_ci		/* Advance to the next DMA scatterlist entry */
11862306a36Sopenharmony_ci		wa->dma_sg = sg_next(wa->dma_sg);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci		/* In the case that the DMA mapped scatterlist has entries
12162306a36Sopenharmony_ci		 * that have been merged, the non-DMA mapped scatterlist
12262306a36Sopenharmony_ci		 * must be advanced multiple times for each merged entry.
12362306a36Sopenharmony_ci		 * This ensures that the current non-DMA mapped entry
12462306a36Sopenharmony_ci		 * corresponds to the current DMA mapped entry.
12562306a36Sopenharmony_ci		 */
12662306a36Sopenharmony_ci		do {
12762306a36Sopenharmony_ci			sg_combined_len += wa->sg->length;
12862306a36Sopenharmony_ci			wa->sg = sg_next(wa->sg);
12962306a36Sopenharmony_ci		} while (wa->sg_used > sg_combined_len);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci		wa->sg_used = 0;
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic void ccp_dm_free(struct ccp_dm_workarea *wa)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	if (wa->length <= CCP_DMAPOOL_MAX_SIZE) {
13862306a36Sopenharmony_ci		if (wa->address)
13962306a36Sopenharmony_ci			dma_pool_free(wa->dma_pool, wa->address,
14062306a36Sopenharmony_ci				      wa->dma.address);
14162306a36Sopenharmony_ci	} else {
14262306a36Sopenharmony_ci		if (wa->dma.address)
14362306a36Sopenharmony_ci			dma_unmap_single(wa->dev, wa->dma.address, wa->length,
14462306a36Sopenharmony_ci					 wa->dma.dir);
14562306a36Sopenharmony_ci		kfree(wa->address);
14662306a36Sopenharmony_ci	}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	wa->address = NULL;
14962306a36Sopenharmony_ci	wa->dma.address = 0;
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic int ccp_init_dm_workarea(struct ccp_dm_workarea *wa,
15362306a36Sopenharmony_ci				struct ccp_cmd_queue *cmd_q,
15462306a36Sopenharmony_ci				unsigned int len,
15562306a36Sopenharmony_ci				enum dma_data_direction dir)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	memset(wa, 0, sizeof(*wa));
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	if (!len)
16062306a36Sopenharmony_ci		return 0;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	wa->dev = cmd_q->ccp->dev;
16362306a36Sopenharmony_ci	wa->length = len;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	if (len <= CCP_DMAPOOL_MAX_SIZE) {
16662306a36Sopenharmony_ci		wa->dma_pool = cmd_q->dma_pool;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci		wa->address = dma_pool_zalloc(wa->dma_pool, GFP_KERNEL,
16962306a36Sopenharmony_ci					     &wa->dma.address);
17062306a36Sopenharmony_ci		if (!wa->address)
17162306a36Sopenharmony_ci			return -ENOMEM;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci		wa->dma.length = CCP_DMAPOOL_MAX_SIZE;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	} else {
17662306a36Sopenharmony_ci		wa->address = kzalloc(len, GFP_KERNEL);
17762306a36Sopenharmony_ci		if (!wa->address)
17862306a36Sopenharmony_ci			return -ENOMEM;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci		wa->dma.address = dma_map_single(wa->dev, wa->address, len,
18162306a36Sopenharmony_ci						 dir);
18262306a36Sopenharmony_ci		if (dma_mapping_error(wa->dev, wa->dma.address)) {
18362306a36Sopenharmony_ci			kfree(wa->address);
18462306a36Sopenharmony_ci			wa->address = NULL;
18562306a36Sopenharmony_ci			return -ENOMEM;
18662306a36Sopenharmony_ci		}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci		wa->dma.length = len;
18962306a36Sopenharmony_ci	}
19062306a36Sopenharmony_ci	wa->dma.dir = dir;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	return 0;
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic int ccp_set_dm_area(struct ccp_dm_workarea *wa, unsigned int wa_offset,
19662306a36Sopenharmony_ci			   struct scatterlist *sg, unsigned int sg_offset,
19762306a36Sopenharmony_ci			   unsigned int len)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	WARN_ON(!wa->address);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	if (len > (wa->length - wa_offset))
20262306a36Sopenharmony_ci		return -EINVAL;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	scatterwalk_map_and_copy(wa->address + wa_offset, sg, sg_offset, len,
20562306a36Sopenharmony_ci				 0);
20662306a36Sopenharmony_ci	return 0;
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_cistatic void ccp_get_dm_area(struct ccp_dm_workarea *wa, unsigned int wa_offset,
21062306a36Sopenharmony_ci			    struct scatterlist *sg, unsigned int sg_offset,
21162306a36Sopenharmony_ci			    unsigned int len)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	WARN_ON(!wa->address);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	scatterwalk_map_and_copy(wa->address + wa_offset, sg, sg_offset, len,
21662306a36Sopenharmony_ci				 1);
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic int ccp_reverse_set_dm_area(struct ccp_dm_workarea *wa,
22062306a36Sopenharmony_ci				   unsigned int wa_offset,
22162306a36Sopenharmony_ci				   struct scatterlist *sg,
22262306a36Sopenharmony_ci				   unsigned int sg_offset,
22362306a36Sopenharmony_ci				   unsigned int len)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	u8 *p, *q;
22662306a36Sopenharmony_ci	int	rc;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	rc = ccp_set_dm_area(wa, wa_offset, sg, sg_offset, len);
22962306a36Sopenharmony_ci	if (rc)
23062306a36Sopenharmony_ci		return rc;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	p = wa->address + wa_offset;
23362306a36Sopenharmony_ci	q = p + len - 1;
23462306a36Sopenharmony_ci	while (p < q) {
23562306a36Sopenharmony_ci		*p = *p ^ *q;
23662306a36Sopenharmony_ci		*q = *p ^ *q;
23762306a36Sopenharmony_ci		*p = *p ^ *q;
23862306a36Sopenharmony_ci		p++;
23962306a36Sopenharmony_ci		q--;
24062306a36Sopenharmony_ci	}
24162306a36Sopenharmony_ci	return 0;
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic void ccp_reverse_get_dm_area(struct ccp_dm_workarea *wa,
24562306a36Sopenharmony_ci				    unsigned int wa_offset,
24662306a36Sopenharmony_ci				    struct scatterlist *sg,
24762306a36Sopenharmony_ci				    unsigned int sg_offset,
24862306a36Sopenharmony_ci				    unsigned int len)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	u8 *p, *q;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	p = wa->address + wa_offset;
25362306a36Sopenharmony_ci	q = p + len - 1;
25462306a36Sopenharmony_ci	while (p < q) {
25562306a36Sopenharmony_ci		*p = *p ^ *q;
25662306a36Sopenharmony_ci		*q = *p ^ *q;
25762306a36Sopenharmony_ci		*p = *p ^ *q;
25862306a36Sopenharmony_ci		p++;
25962306a36Sopenharmony_ci		q--;
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	ccp_get_dm_area(wa, wa_offset, sg, sg_offset, len);
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cistatic void ccp_free_data(struct ccp_data *data, struct ccp_cmd_queue *cmd_q)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	ccp_dm_free(&data->dm_wa);
26862306a36Sopenharmony_ci	ccp_sg_free(&data->sg_wa);
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic int ccp_init_data(struct ccp_data *data, struct ccp_cmd_queue *cmd_q,
27262306a36Sopenharmony_ci			 struct scatterlist *sg, u64 sg_len,
27362306a36Sopenharmony_ci			 unsigned int dm_len,
27462306a36Sopenharmony_ci			 enum dma_data_direction dir)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	int ret;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	memset(data, 0, sizeof(*data));
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	ret = ccp_init_sg_workarea(&data->sg_wa, cmd_q->ccp->dev, sg, sg_len,
28162306a36Sopenharmony_ci				   dir);
28262306a36Sopenharmony_ci	if (ret)
28362306a36Sopenharmony_ci		goto e_err;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	ret = ccp_init_dm_workarea(&data->dm_wa, cmd_q, dm_len, dir);
28662306a36Sopenharmony_ci	if (ret)
28762306a36Sopenharmony_ci		goto e_err;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	return 0;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cie_err:
29262306a36Sopenharmony_ci	ccp_free_data(data, cmd_q);
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	return ret;
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_cistatic unsigned int ccp_queue_buf(struct ccp_data *data, unsigned int from)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	struct ccp_sg_workarea *sg_wa = &data->sg_wa;
30062306a36Sopenharmony_ci	struct ccp_dm_workarea *dm_wa = &data->dm_wa;
30162306a36Sopenharmony_ci	unsigned int buf_count, nbytes;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	/* Clear the buffer if setting it */
30462306a36Sopenharmony_ci	if (!from)
30562306a36Sopenharmony_ci		memset(dm_wa->address, 0, dm_wa->length);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	if (!sg_wa->sg)
30862306a36Sopenharmony_ci		return 0;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	/* Perform the copy operation
31162306a36Sopenharmony_ci	 *   nbytes will always be <= UINT_MAX because dm_wa->length is
31262306a36Sopenharmony_ci	 *   an unsigned int
31362306a36Sopenharmony_ci	 */
31462306a36Sopenharmony_ci	nbytes = min_t(u64, sg_wa->bytes_left, dm_wa->length);
31562306a36Sopenharmony_ci	scatterwalk_map_and_copy(dm_wa->address, sg_wa->sg, sg_wa->sg_used,
31662306a36Sopenharmony_ci				 nbytes, from);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	/* Update the structures and generate the count */
31962306a36Sopenharmony_ci	buf_count = 0;
32062306a36Sopenharmony_ci	while (sg_wa->bytes_left && (buf_count < dm_wa->length)) {
32162306a36Sopenharmony_ci		nbytes = min(sg_dma_len(sg_wa->dma_sg) - sg_wa->sg_used,
32262306a36Sopenharmony_ci			     dm_wa->length - buf_count);
32362306a36Sopenharmony_ci		nbytes = min_t(u64, sg_wa->bytes_left, nbytes);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci		buf_count += nbytes;
32662306a36Sopenharmony_ci		ccp_update_sg_workarea(sg_wa, nbytes);
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	return buf_count;
33062306a36Sopenharmony_ci}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_cistatic unsigned int ccp_fill_queue_buf(struct ccp_data *data)
33362306a36Sopenharmony_ci{
33462306a36Sopenharmony_ci	return ccp_queue_buf(data, 0);
33562306a36Sopenharmony_ci}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_cistatic unsigned int ccp_empty_queue_buf(struct ccp_data *data)
33862306a36Sopenharmony_ci{
33962306a36Sopenharmony_ci	return ccp_queue_buf(data, 1);
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_cistatic void ccp_prepare_data(struct ccp_data *src, struct ccp_data *dst,
34362306a36Sopenharmony_ci			     struct ccp_op *op, unsigned int block_size,
34462306a36Sopenharmony_ci			     bool blocksize_op)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	unsigned int sg_src_len, sg_dst_len, op_len;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	/* The CCP can only DMA from/to one address each per operation. This
34962306a36Sopenharmony_ci	 * requires that we find the smallest DMA area between the source
35062306a36Sopenharmony_ci	 * and destination. The resulting len values will always be <= UINT_MAX
35162306a36Sopenharmony_ci	 * because the dma length is an unsigned int.
35262306a36Sopenharmony_ci	 */
35362306a36Sopenharmony_ci	sg_src_len = sg_dma_len(src->sg_wa.dma_sg) - src->sg_wa.sg_used;
35462306a36Sopenharmony_ci	sg_src_len = min_t(u64, src->sg_wa.bytes_left, sg_src_len);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	if (dst) {
35762306a36Sopenharmony_ci		sg_dst_len = sg_dma_len(dst->sg_wa.dma_sg) - dst->sg_wa.sg_used;
35862306a36Sopenharmony_ci		sg_dst_len = min_t(u64, src->sg_wa.bytes_left, sg_dst_len);
35962306a36Sopenharmony_ci		op_len = min(sg_src_len, sg_dst_len);
36062306a36Sopenharmony_ci	} else {
36162306a36Sopenharmony_ci		op_len = sg_src_len;
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	/* The data operation length will be at least block_size in length
36562306a36Sopenharmony_ci	 * or the smaller of available sg room remaining for the source or
36662306a36Sopenharmony_ci	 * the destination
36762306a36Sopenharmony_ci	 */
36862306a36Sopenharmony_ci	op_len = max(op_len, block_size);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	/* Unless we have to buffer data, there's no reason to wait */
37162306a36Sopenharmony_ci	op->soc = 0;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	if (sg_src_len < block_size) {
37462306a36Sopenharmony_ci		/* Not enough data in the sg element, so it
37562306a36Sopenharmony_ci		 * needs to be buffered into a blocksize chunk
37662306a36Sopenharmony_ci		 */
37762306a36Sopenharmony_ci		int cp_len = ccp_fill_queue_buf(src);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci		op->soc = 1;
38062306a36Sopenharmony_ci		op->src.u.dma.address = src->dm_wa.dma.address;
38162306a36Sopenharmony_ci		op->src.u.dma.offset = 0;
38262306a36Sopenharmony_ci		op->src.u.dma.length = (blocksize_op) ? block_size : cp_len;
38362306a36Sopenharmony_ci	} else {
38462306a36Sopenharmony_ci		/* Enough data in the sg element, but we need to
38562306a36Sopenharmony_ci		 * adjust for any previously copied data
38662306a36Sopenharmony_ci		 */
38762306a36Sopenharmony_ci		op->src.u.dma.address = sg_dma_address(src->sg_wa.dma_sg);
38862306a36Sopenharmony_ci		op->src.u.dma.offset = src->sg_wa.sg_used;
38962306a36Sopenharmony_ci		op->src.u.dma.length = op_len & ~(block_size - 1);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci		ccp_update_sg_workarea(&src->sg_wa, op->src.u.dma.length);
39262306a36Sopenharmony_ci	}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	if (dst) {
39562306a36Sopenharmony_ci		if (sg_dst_len < block_size) {
39662306a36Sopenharmony_ci			/* Not enough room in the sg element or we're on the
39762306a36Sopenharmony_ci			 * last piece of data (when using padding), so the
39862306a36Sopenharmony_ci			 * output needs to be buffered into a blocksize chunk
39962306a36Sopenharmony_ci			 */
40062306a36Sopenharmony_ci			op->soc = 1;
40162306a36Sopenharmony_ci			op->dst.u.dma.address = dst->dm_wa.dma.address;
40262306a36Sopenharmony_ci			op->dst.u.dma.offset = 0;
40362306a36Sopenharmony_ci			op->dst.u.dma.length = op->src.u.dma.length;
40462306a36Sopenharmony_ci		} else {
40562306a36Sopenharmony_ci			/* Enough room in the sg element, but we need to
40662306a36Sopenharmony_ci			 * adjust for any previously used area
40762306a36Sopenharmony_ci			 */
40862306a36Sopenharmony_ci			op->dst.u.dma.address = sg_dma_address(dst->sg_wa.dma_sg);
40962306a36Sopenharmony_ci			op->dst.u.dma.offset = dst->sg_wa.sg_used;
41062306a36Sopenharmony_ci			op->dst.u.dma.length = op->src.u.dma.length;
41162306a36Sopenharmony_ci		}
41262306a36Sopenharmony_ci	}
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cistatic void ccp_process_data(struct ccp_data *src, struct ccp_data *dst,
41662306a36Sopenharmony_ci			     struct ccp_op *op)
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	op->init = 0;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	if (dst) {
42162306a36Sopenharmony_ci		if (op->dst.u.dma.address == dst->dm_wa.dma.address)
42262306a36Sopenharmony_ci			ccp_empty_queue_buf(dst);
42362306a36Sopenharmony_ci		else
42462306a36Sopenharmony_ci			ccp_update_sg_workarea(&dst->sg_wa,
42562306a36Sopenharmony_ci					       op->dst.u.dma.length);
42662306a36Sopenharmony_ci	}
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_cistatic int ccp_copy_to_from_sb(struct ccp_cmd_queue *cmd_q,
43062306a36Sopenharmony_ci			       struct ccp_dm_workarea *wa, u32 jobid, u32 sb,
43162306a36Sopenharmony_ci			       u32 byte_swap, bool from)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	struct ccp_op op;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	memset(&op, 0, sizeof(op));
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	op.cmd_q = cmd_q;
43862306a36Sopenharmony_ci	op.jobid = jobid;
43962306a36Sopenharmony_ci	op.eom = 1;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	if (from) {
44262306a36Sopenharmony_ci		op.soc = 1;
44362306a36Sopenharmony_ci		op.src.type = CCP_MEMTYPE_SB;
44462306a36Sopenharmony_ci		op.src.u.sb = sb;
44562306a36Sopenharmony_ci		op.dst.type = CCP_MEMTYPE_SYSTEM;
44662306a36Sopenharmony_ci		op.dst.u.dma.address = wa->dma.address;
44762306a36Sopenharmony_ci		op.dst.u.dma.length = wa->length;
44862306a36Sopenharmony_ci	} else {
44962306a36Sopenharmony_ci		op.src.type = CCP_MEMTYPE_SYSTEM;
45062306a36Sopenharmony_ci		op.src.u.dma.address = wa->dma.address;
45162306a36Sopenharmony_ci		op.src.u.dma.length = wa->length;
45262306a36Sopenharmony_ci		op.dst.type = CCP_MEMTYPE_SB;
45362306a36Sopenharmony_ci		op.dst.u.sb = sb;
45462306a36Sopenharmony_ci	}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	op.u.passthru.byte_swap = byte_swap;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	return cmd_q->ccp->vdata->perform->passthru(&op);
45962306a36Sopenharmony_ci}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_cistatic int ccp_copy_to_sb(struct ccp_cmd_queue *cmd_q,
46262306a36Sopenharmony_ci			  struct ccp_dm_workarea *wa, u32 jobid, u32 sb,
46362306a36Sopenharmony_ci			  u32 byte_swap)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	return ccp_copy_to_from_sb(cmd_q, wa, jobid, sb, byte_swap, false);
46662306a36Sopenharmony_ci}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_cistatic int ccp_copy_from_sb(struct ccp_cmd_queue *cmd_q,
46962306a36Sopenharmony_ci			    struct ccp_dm_workarea *wa, u32 jobid, u32 sb,
47062306a36Sopenharmony_ci			    u32 byte_swap)
47162306a36Sopenharmony_ci{
47262306a36Sopenharmony_ci	return ccp_copy_to_from_sb(cmd_q, wa, jobid, sb, byte_swap, true);
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_cistatic noinline_for_stack int
47662306a36Sopenharmony_ciccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	struct ccp_aes_engine *aes = &cmd->u.aes;
47962306a36Sopenharmony_ci	struct ccp_dm_workarea key, ctx;
48062306a36Sopenharmony_ci	struct ccp_data src;
48162306a36Sopenharmony_ci	struct ccp_op op;
48262306a36Sopenharmony_ci	unsigned int dm_offset;
48362306a36Sopenharmony_ci	int ret;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	if (!((aes->key_len == AES_KEYSIZE_128) ||
48662306a36Sopenharmony_ci	      (aes->key_len == AES_KEYSIZE_192) ||
48762306a36Sopenharmony_ci	      (aes->key_len == AES_KEYSIZE_256)))
48862306a36Sopenharmony_ci		return -EINVAL;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	if (aes->src_len & (AES_BLOCK_SIZE - 1))
49162306a36Sopenharmony_ci		return -EINVAL;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	if (aes->iv_len != AES_BLOCK_SIZE)
49462306a36Sopenharmony_ci		return -EINVAL;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	if (!aes->key || !aes->iv || !aes->src)
49762306a36Sopenharmony_ci		return -EINVAL;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	if (aes->cmac_final) {
50062306a36Sopenharmony_ci		if (aes->cmac_key_len != AES_BLOCK_SIZE)
50162306a36Sopenharmony_ci			return -EINVAL;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci		if (!aes->cmac_key)
50462306a36Sopenharmony_ci			return -EINVAL;
50562306a36Sopenharmony_ci	}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	BUILD_BUG_ON(CCP_AES_KEY_SB_COUNT != 1);
50862306a36Sopenharmony_ci	BUILD_BUG_ON(CCP_AES_CTX_SB_COUNT != 1);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	ret = -EIO;
51162306a36Sopenharmony_ci	memset(&op, 0, sizeof(op));
51262306a36Sopenharmony_ci	op.cmd_q = cmd_q;
51362306a36Sopenharmony_ci	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
51462306a36Sopenharmony_ci	op.sb_key = cmd_q->sb_key;
51562306a36Sopenharmony_ci	op.sb_ctx = cmd_q->sb_ctx;
51662306a36Sopenharmony_ci	op.init = 1;
51762306a36Sopenharmony_ci	op.u.aes.type = aes->type;
51862306a36Sopenharmony_ci	op.u.aes.mode = aes->mode;
51962306a36Sopenharmony_ci	op.u.aes.action = aes->action;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	/* All supported key sizes fit in a single (32-byte) SB entry
52262306a36Sopenharmony_ci	 * and must be in little endian format. Use the 256-bit byte
52362306a36Sopenharmony_ci	 * swap passthru option to convert from big endian to little
52462306a36Sopenharmony_ci	 * endian.
52562306a36Sopenharmony_ci	 */
52662306a36Sopenharmony_ci	ret = ccp_init_dm_workarea(&key, cmd_q,
52762306a36Sopenharmony_ci				   CCP_AES_KEY_SB_COUNT * CCP_SB_BYTES,
52862306a36Sopenharmony_ci				   DMA_TO_DEVICE);
52962306a36Sopenharmony_ci	if (ret)
53062306a36Sopenharmony_ci		return ret;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	dm_offset = CCP_SB_BYTES - aes->key_len;
53362306a36Sopenharmony_ci	ret = ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len);
53462306a36Sopenharmony_ci	if (ret)
53562306a36Sopenharmony_ci		goto e_key;
53662306a36Sopenharmony_ci	ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
53762306a36Sopenharmony_ci			     CCP_PASSTHRU_BYTESWAP_256BIT);
53862306a36Sopenharmony_ci	if (ret) {
53962306a36Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
54062306a36Sopenharmony_ci		goto e_key;
54162306a36Sopenharmony_ci	}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	/* The AES context fits in a single (32-byte) SB entry and
54462306a36Sopenharmony_ci	 * must be in little endian format. Use the 256-bit byte swap
54562306a36Sopenharmony_ci	 * passthru option to convert from big endian to little endian.
54662306a36Sopenharmony_ci	 */
54762306a36Sopenharmony_ci	ret = ccp_init_dm_workarea(&ctx, cmd_q,
54862306a36Sopenharmony_ci				   CCP_AES_CTX_SB_COUNT * CCP_SB_BYTES,
54962306a36Sopenharmony_ci				   DMA_BIDIRECTIONAL);
55062306a36Sopenharmony_ci	if (ret)
55162306a36Sopenharmony_ci		goto e_key;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
55462306a36Sopenharmony_ci	ret = ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
55562306a36Sopenharmony_ci	if (ret)
55662306a36Sopenharmony_ci		goto e_ctx;
55762306a36Sopenharmony_ci	ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
55862306a36Sopenharmony_ci			     CCP_PASSTHRU_BYTESWAP_256BIT);
55962306a36Sopenharmony_ci	if (ret) {
56062306a36Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
56162306a36Sopenharmony_ci		goto e_ctx;
56262306a36Sopenharmony_ci	}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	/* Send data to the CCP AES engine */
56562306a36Sopenharmony_ci	ret = ccp_init_data(&src, cmd_q, aes->src, aes->src_len,
56662306a36Sopenharmony_ci			    AES_BLOCK_SIZE, DMA_TO_DEVICE);
56762306a36Sopenharmony_ci	if (ret)
56862306a36Sopenharmony_ci		goto e_ctx;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	while (src.sg_wa.bytes_left) {
57162306a36Sopenharmony_ci		ccp_prepare_data(&src, NULL, &op, AES_BLOCK_SIZE, true);
57262306a36Sopenharmony_ci		if (aes->cmac_final && !src.sg_wa.bytes_left) {
57362306a36Sopenharmony_ci			op.eom = 1;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci			/* Push the K1/K2 key to the CCP now */
57662306a36Sopenharmony_ci			ret = ccp_copy_from_sb(cmd_q, &ctx, op.jobid,
57762306a36Sopenharmony_ci					       op.sb_ctx,
57862306a36Sopenharmony_ci					       CCP_PASSTHRU_BYTESWAP_256BIT);
57962306a36Sopenharmony_ci			if (ret) {
58062306a36Sopenharmony_ci				cmd->engine_error = cmd_q->cmd_error;
58162306a36Sopenharmony_ci				goto e_src;
58262306a36Sopenharmony_ci			}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci			ret = ccp_set_dm_area(&ctx, 0, aes->cmac_key, 0,
58562306a36Sopenharmony_ci					      aes->cmac_key_len);
58662306a36Sopenharmony_ci			if (ret)
58762306a36Sopenharmony_ci				goto e_src;
58862306a36Sopenharmony_ci			ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
58962306a36Sopenharmony_ci					     CCP_PASSTHRU_BYTESWAP_256BIT);
59062306a36Sopenharmony_ci			if (ret) {
59162306a36Sopenharmony_ci				cmd->engine_error = cmd_q->cmd_error;
59262306a36Sopenharmony_ci				goto e_src;
59362306a36Sopenharmony_ci			}
59462306a36Sopenharmony_ci		}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci		ret = cmd_q->ccp->vdata->perform->aes(&op);
59762306a36Sopenharmony_ci		if (ret) {
59862306a36Sopenharmony_ci			cmd->engine_error = cmd_q->cmd_error;
59962306a36Sopenharmony_ci			goto e_src;
60062306a36Sopenharmony_ci		}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci		ccp_process_data(&src, NULL, &op);
60362306a36Sopenharmony_ci	}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	/* Retrieve the AES context - convert from LE to BE using
60662306a36Sopenharmony_ci	 * 32-byte (256-bit) byteswapping
60762306a36Sopenharmony_ci	 */
60862306a36Sopenharmony_ci	ret = ccp_copy_from_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
60962306a36Sopenharmony_ci			       CCP_PASSTHRU_BYTESWAP_256BIT);
61062306a36Sopenharmony_ci	if (ret) {
61162306a36Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
61262306a36Sopenharmony_ci		goto e_src;
61362306a36Sopenharmony_ci	}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	/* ...but we only need AES_BLOCK_SIZE bytes */
61662306a36Sopenharmony_ci	dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
61762306a36Sopenharmony_ci	ccp_get_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_cie_src:
62062306a36Sopenharmony_ci	ccp_free_data(&src, cmd_q);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_cie_ctx:
62362306a36Sopenharmony_ci	ccp_dm_free(&ctx);
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_cie_key:
62662306a36Sopenharmony_ci	ccp_dm_free(&key);
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	return ret;
62962306a36Sopenharmony_ci}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_cistatic noinline_for_stack int
63262306a36Sopenharmony_ciccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
63362306a36Sopenharmony_ci{
63462306a36Sopenharmony_ci	struct ccp_aes_engine *aes = &cmd->u.aes;
63562306a36Sopenharmony_ci	struct ccp_dm_workarea key, ctx, final_wa, tag;
63662306a36Sopenharmony_ci	struct ccp_data src, dst;
63762306a36Sopenharmony_ci	struct ccp_data aad;
63862306a36Sopenharmony_ci	struct ccp_op op;
63962306a36Sopenharmony_ci	unsigned int dm_offset;
64062306a36Sopenharmony_ci	unsigned int authsize;
64162306a36Sopenharmony_ci	unsigned int jobid;
64262306a36Sopenharmony_ci	unsigned int ilen;
64362306a36Sopenharmony_ci	bool in_place = true; /* Default value */
64462306a36Sopenharmony_ci	__be64 *final;
64562306a36Sopenharmony_ci	int ret;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	struct scatterlist *p_inp, sg_inp[2];
64862306a36Sopenharmony_ci	struct scatterlist *p_tag, sg_tag[2];
64962306a36Sopenharmony_ci	struct scatterlist *p_outp, sg_outp[2];
65062306a36Sopenharmony_ci	struct scatterlist *p_aad;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	if (!aes->iv)
65362306a36Sopenharmony_ci		return -EINVAL;
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	if (!((aes->key_len == AES_KEYSIZE_128) ||
65662306a36Sopenharmony_ci		(aes->key_len == AES_KEYSIZE_192) ||
65762306a36Sopenharmony_ci		(aes->key_len == AES_KEYSIZE_256)))
65862306a36Sopenharmony_ci		return -EINVAL;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	if (!aes->key) /* Gotta have a key SGL */
66162306a36Sopenharmony_ci		return -EINVAL;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	/* Zero defaults to 16 bytes, the maximum size */
66462306a36Sopenharmony_ci	authsize = aes->authsize ? aes->authsize : AES_BLOCK_SIZE;
66562306a36Sopenharmony_ci	switch (authsize) {
66662306a36Sopenharmony_ci	case 16:
66762306a36Sopenharmony_ci	case 15:
66862306a36Sopenharmony_ci	case 14:
66962306a36Sopenharmony_ci	case 13:
67062306a36Sopenharmony_ci	case 12:
67162306a36Sopenharmony_ci	case 8:
67262306a36Sopenharmony_ci	case 4:
67362306a36Sopenharmony_ci		break;
67462306a36Sopenharmony_ci	default:
67562306a36Sopenharmony_ci		return -EINVAL;
67662306a36Sopenharmony_ci	}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	/* First, decompose the source buffer into AAD & PT,
67962306a36Sopenharmony_ci	 * and the destination buffer into AAD, CT & tag, or
68062306a36Sopenharmony_ci	 * the input into CT & tag.
68162306a36Sopenharmony_ci	 * It is expected that the input and output SGs will
68262306a36Sopenharmony_ci	 * be valid, even if the AAD and input lengths are 0.
68362306a36Sopenharmony_ci	 */
68462306a36Sopenharmony_ci	p_aad = aes->src;
68562306a36Sopenharmony_ci	p_inp = scatterwalk_ffwd(sg_inp, aes->src, aes->aad_len);
68662306a36Sopenharmony_ci	p_outp = scatterwalk_ffwd(sg_outp, aes->dst, aes->aad_len);
68762306a36Sopenharmony_ci	if (aes->action == CCP_AES_ACTION_ENCRYPT) {
68862306a36Sopenharmony_ci		ilen = aes->src_len;
68962306a36Sopenharmony_ci		p_tag = scatterwalk_ffwd(sg_tag, p_outp, ilen);
69062306a36Sopenharmony_ci	} else {
69162306a36Sopenharmony_ci		/* Input length for decryption includes tag */
69262306a36Sopenharmony_ci		ilen = aes->src_len - authsize;
69362306a36Sopenharmony_ci		p_tag = scatterwalk_ffwd(sg_tag, p_inp, ilen);
69462306a36Sopenharmony_ci	}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	jobid = CCP_NEW_JOBID(cmd_q->ccp);
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	memset(&op, 0, sizeof(op));
69962306a36Sopenharmony_ci	op.cmd_q = cmd_q;
70062306a36Sopenharmony_ci	op.jobid = jobid;
70162306a36Sopenharmony_ci	op.sb_key = cmd_q->sb_key; /* Pre-allocated */
70262306a36Sopenharmony_ci	op.sb_ctx = cmd_q->sb_ctx; /* Pre-allocated */
70362306a36Sopenharmony_ci	op.init = 1;
70462306a36Sopenharmony_ci	op.u.aes.type = aes->type;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	/* Copy the key to the LSB */
70762306a36Sopenharmony_ci	ret = ccp_init_dm_workarea(&key, cmd_q,
70862306a36Sopenharmony_ci				   CCP_AES_CTX_SB_COUNT * CCP_SB_BYTES,
70962306a36Sopenharmony_ci				   DMA_TO_DEVICE);
71062306a36Sopenharmony_ci	if (ret)
71162306a36Sopenharmony_ci		return ret;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	dm_offset = CCP_SB_BYTES - aes->key_len;
71462306a36Sopenharmony_ci	ret = ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len);
71562306a36Sopenharmony_ci	if (ret)
71662306a36Sopenharmony_ci		goto e_key;
71762306a36Sopenharmony_ci	ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
71862306a36Sopenharmony_ci			     CCP_PASSTHRU_BYTESWAP_256BIT);
71962306a36Sopenharmony_ci	if (ret) {
72062306a36Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
72162306a36Sopenharmony_ci		goto e_key;
72262306a36Sopenharmony_ci	}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	/* Copy the context (IV) to the LSB.
72562306a36Sopenharmony_ci	 * There is an assumption here that the IV is 96 bits in length, plus
72662306a36Sopenharmony_ci	 * a nonce of 32 bits. If no IV is present, use a zeroed buffer.
72762306a36Sopenharmony_ci	 */
72862306a36Sopenharmony_ci	ret = ccp_init_dm_workarea(&ctx, cmd_q,
72962306a36Sopenharmony_ci				   CCP_AES_CTX_SB_COUNT * CCP_SB_BYTES,
73062306a36Sopenharmony_ci				   DMA_BIDIRECTIONAL);
73162306a36Sopenharmony_ci	if (ret)
73262306a36Sopenharmony_ci		goto e_key;
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	dm_offset = CCP_AES_CTX_SB_COUNT * CCP_SB_BYTES - aes->iv_len;
73562306a36Sopenharmony_ci	ret = ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
73662306a36Sopenharmony_ci	if (ret)
73762306a36Sopenharmony_ci		goto e_ctx;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
74062306a36Sopenharmony_ci			     CCP_PASSTHRU_BYTESWAP_256BIT);
74162306a36Sopenharmony_ci	if (ret) {
74262306a36Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
74362306a36Sopenharmony_ci		goto e_ctx;
74462306a36Sopenharmony_ci	}
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	op.init = 1;
74762306a36Sopenharmony_ci	if (aes->aad_len > 0) {
74862306a36Sopenharmony_ci		/* Step 1: Run a GHASH over the Additional Authenticated Data */
74962306a36Sopenharmony_ci		ret = ccp_init_data(&aad, cmd_q, p_aad, aes->aad_len,
75062306a36Sopenharmony_ci				    AES_BLOCK_SIZE,
75162306a36Sopenharmony_ci				    DMA_TO_DEVICE);
75262306a36Sopenharmony_ci		if (ret)
75362306a36Sopenharmony_ci			goto e_ctx;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci		op.u.aes.mode = CCP_AES_MODE_GHASH;
75662306a36Sopenharmony_ci		op.u.aes.action = CCP_AES_GHASHAAD;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci		while (aad.sg_wa.bytes_left) {
75962306a36Sopenharmony_ci			ccp_prepare_data(&aad, NULL, &op, AES_BLOCK_SIZE, true);
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci			ret = cmd_q->ccp->vdata->perform->aes(&op);
76262306a36Sopenharmony_ci			if (ret) {
76362306a36Sopenharmony_ci				cmd->engine_error = cmd_q->cmd_error;
76462306a36Sopenharmony_ci				goto e_aad;
76562306a36Sopenharmony_ci			}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci			ccp_process_data(&aad, NULL, &op);
76862306a36Sopenharmony_ci			op.init = 0;
76962306a36Sopenharmony_ci		}
77062306a36Sopenharmony_ci	}
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	op.u.aes.mode = CCP_AES_MODE_GCTR;
77362306a36Sopenharmony_ci	op.u.aes.action = aes->action;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	if (ilen > 0) {
77662306a36Sopenharmony_ci		/* Step 2: Run a GCTR over the plaintext */
77762306a36Sopenharmony_ci		in_place = (sg_virt(p_inp) == sg_virt(p_outp)) ? true : false;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci		ret = ccp_init_data(&src, cmd_q, p_inp, ilen,
78062306a36Sopenharmony_ci				    AES_BLOCK_SIZE,
78162306a36Sopenharmony_ci				    in_place ? DMA_BIDIRECTIONAL
78262306a36Sopenharmony_ci					     : DMA_TO_DEVICE);
78362306a36Sopenharmony_ci		if (ret)
78462306a36Sopenharmony_ci			goto e_aad;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci		if (in_place) {
78762306a36Sopenharmony_ci			dst = src;
78862306a36Sopenharmony_ci		} else {
78962306a36Sopenharmony_ci			ret = ccp_init_data(&dst, cmd_q, p_outp, ilen,
79062306a36Sopenharmony_ci					    AES_BLOCK_SIZE, DMA_FROM_DEVICE);
79162306a36Sopenharmony_ci			if (ret)
79262306a36Sopenharmony_ci				goto e_src;
79362306a36Sopenharmony_ci		}
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci		op.soc = 0;
79662306a36Sopenharmony_ci		op.eom = 0;
79762306a36Sopenharmony_ci		op.init = 1;
79862306a36Sopenharmony_ci		while (src.sg_wa.bytes_left) {
79962306a36Sopenharmony_ci			ccp_prepare_data(&src, &dst, &op, AES_BLOCK_SIZE, true);
80062306a36Sopenharmony_ci			if (!src.sg_wa.bytes_left) {
80162306a36Sopenharmony_ci				unsigned int nbytes = ilen % AES_BLOCK_SIZE;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci				if (nbytes) {
80462306a36Sopenharmony_ci					op.eom = 1;
80562306a36Sopenharmony_ci					op.u.aes.size = (nbytes * 8) - 1;
80662306a36Sopenharmony_ci				}
80762306a36Sopenharmony_ci			}
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci			ret = cmd_q->ccp->vdata->perform->aes(&op);
81062306a36Sopenharmony_ci			if (ret) {
81162306a36Sopenharmony_ci				cmd->engine_error = cmd_q->cmd_error;
81262306a36Sopenharmony_ci				goto e_dst;
81362306a36Sopenharmony_ci			}
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci			ccp_process_data(&src, &dst, &op);
81662306a36Sopenharmony_ci			op.init = 0;
81762306a36Sopenharmony_ci		}
81862306a36Sopenharmony_ci	}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	/* Step 3: Update the IV portion of the context with the original IV */
82162306a36Sopenharmony_ci	ret = ccp_copy_from_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
82262306a36Sopenharmony_ci			       CCP_PASSTHRU_BYTESWAP_256BIT);
82362306a36Sopenharmony_ci	if (ret) {
82462306a36Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
82562306a36Sopenharmony_ci		goto e_dst;
82662306a36Sopenharmony_ci	}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	ret = ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
82962306a36Sopenharmony_ci	if (ret)
83062306a36Sopenharmony_ci		goto e_dst;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
83362306a36Sopenharmony_ci			     CCP_PASSTHRU_BYTESWAP_256BIT);
83462306a36Sopenharmony_ci	if (ret) {
83562306a36Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
83662306a36Sopenharmony_ci		goto e_dst;
83762306a36Sopenharmony_ci	}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	/* Step 4: Concatenate the lengths of the AAD and source, and
84062306a36Sopenharmony_ci	 * hash that 16 byte buffer.
84162306a36Sopenharmony_ci	 */
84262306a36Sopenharmony_ci	ret = ccp_init_dm_workarea(&final_wa, cmd_q, AES_BLOCK_SIZE,
84362306a36Sopenharmony_ci				   DMA_BIDIRECTIONAL);
84462306a36Sopenharmony_ci	if (ret)
84562306a36Sopenharmony_ci		goto e_dst;
84662306a36Sopenharmony_ci	final = (__be64 *)final_wa.address;
84762306a36Sopenharmony_ci	final[0] = cpu_to_be64(aes->aad_len * 8);
84862306a36Sopenharmony_ci	final[1] = cpu_to_be64(ilen * 8);
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	memset(&op, 0, sizeof(op));
85162306a36Sopenharmony_ci	op.cmd_q = cmd_q;
85262306a36Sopenharmony_ci	op.jobid = jobid;
85362306a36Sopenharmony_ci	op.sb_key = cmd_q->sb_key; /* Pre-allocated */
85462306a36Sopenharmony_ci	op.sb_ctx = cmd_q->sb_ctx; /* Pre-allocated */
85562306a36Sopenharmony_ci	op.init = 1;
85662306a36Sopenharmony_ci	op.u.aes.type = aes->type;
85762306a36Sopenharmony_ci	op.u.aes.mode = CCP_AES_MODE_GHASH;
85862306a36Sopenharmony_ci	op.u.aes.action = CCP_AES_GHASHFINAL;
85962306a36Sopenharmony_ci	op.src.type = CCP_MEMTYPE_SYSTEM;
86062306a36Sopenharmony_ci	op.src.u.dma.address = final_wa.dma.address;
86162306a36Sopenharmony_ci	op.src.u.dma.length = AES_BLOCK_SIZE;
86262306a36Sopenharmony_ci	op.dst.type = CCP_MEMTYPE_SYSTEM;
86362306a36Sopenharmony_ci	op.dst.u.dma.address = final_wa.dma.address;
86462306a36Sopenharmony_ci	op.dst.u.dma.length = AES_BLOCK_SIZE;
86562306a36Sopenharmony_ci	op.eom = 1;
86662306a36Sopenharmony_ci	op.u.aes.size = 0;
86762306a36Sopenharmony_ci	ret = cmd_q->ccp->vdata->perform->aes(&op);
86862306a36Sopenharmony_ci	if (ret)
86962306a36Sopenharmony_ci		goto e_final_wa;
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	if (aes->action == CCP_AES_ACTION_ENCRYPT) {
87262306a36Sopenharmony_ci		/* Put the ciphered tag after the ciphertext. */
87362306a36Sopenharmony_ci		ccp_get_dm_area(&final_wa, 0, p_tag, 0, authsize);
87462306a36Sopenharmony_ci	} else {
87562306a36Sopenharmony_ci		/* Does this ciphered tag match the input? */
87662306a36Sopenharmony_ci		ret = ccp_init_dm_workarea(&tag, cmd_q, authsize,
87762306a36Sopenharmony_ci					   DMA_BIDIRECTIONAL);
87862306a36Sopenharmony_ci		if (ret)
87962306a36Sopenharmony_ci			goto e_final_wa;
88062306a36Sopenharmony_ci		ret = ccp_set_dm_area(&tag, 0, p_tag, 0, authsize);
88162306a36Sopenharmony_ci		if (ret) {
88262306a36Sopenharmony_ci			ccp_dm_free(&tag);
88362306a36Sopenharmony_ci			goto e_final_wa;
88462306a36Sopenharmony_ci		}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci		ret = crypto_memneq(tag.address, final_wa.address,
88762306a36Sopenharmony_ci				    authsize) ? -EBADMSG : 0;
88862306a36Sopenharmony_ci		ccp_dm_free(&tag);
88962306a36Sopenharmony_ci	}
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_cie_final_wa:
89262306a36Sopenharmony_ci	ccp_dm_free(&final_wa);
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_cie_dst:
89562306a36Sopenharmony_ci	if (ilen > 0 && !in_place)
89662306a36Sopenharmony_ci		ccp_free_data(&dst, cmd_q);
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_cie_src:
89962306a36Sopenharmony_ci	if (ilen > 0)
90062306a36Sopenharmony_ci		ccp_free_data(&src, cmd_q);
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_cie_aad:
90362306a36Sopenharmony_ci	if (aes->aad_len)
90462306a36Sopenharmony_ci		ccp_free_data(&aad, cmd_q);
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_cie_ctx:
90762306a36Sopenharmony_ci	ccp_dm_free(&ctx);
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_cie_key:
91062306a36Sopenharmony_ci	ccp_dm_free(&key);
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	return ret;
91362306a36Sopenharmony_ci}
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_cistatic noinline_for_stack int
91662306a36Sopenharmony_ciccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
91762306a36Sopenharmony_ci{
91862306a36Sopenharmony_ci	struct ccp_aes_engine *aes = &cmd->u.aes;
91962306a36Sopenharmony_ci	struct ccp_dm_workarea key, ctx;
92062306a36Sopenharmony_ci	struct ccp_data src, dst;
92162306a36Sopenharmony_ci	struct ccp_op op;
92262306a36Sopenharmony_ci	unsigned int dm_offset;
92362306a36Sopenharmony_ci	bool in_place = false;
92462306a36Sopenharmony_ci	int ret;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	if (!((aes->key_len == AES_KEYSIZE_128) ||
92762306a36Sopenharmony_ci	      (aes->key_len == AES_KEYSIZE_192) ||
92862306a36Sopenharmony_ci	      (aes->key_len == AES_KEYSIZE_256)))
92962306a36Sopenharmony_ci		return -EINVAL;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	if (((aes->mode == CCP_AES_MODE_ECB) ||
93262306a36Sopenharmony_ci	     (aes->mode == CCP_AES_MODE_CBC)) &&
93362306a36Sopenharmony_ci	    (aes->src_len & (AES_BLOCK_SIZE - 1)))
93462306a36Sopenharmony_ci		return -EINVAL;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	if (!aes->key || !aes->src || !aes->dst)
93762306a36Sopenharmony_ci		return -EINVAL;
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	if (aes->mode != CCP_AES_MODE_ECB) {
94062306a36Sopenharmony_ci		if (aes->iv_len != AES_BLOCK_SIZE)
94162306a36Sopenharmony_ci			return -EINVAL;
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci		if (!aes->iv)
94462306a36Sopenharmony_ci			return -EINVAL;
94562306a36Sopenharmony_ci	}
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	BUILD_BUG_ON(CCP_AES_KEY_SB_COUNT != 1);
94862306a36Sopenharmony_ci	BUILD_BUG_ON(CCP_AES_CTX_SB_COUNT != 1);
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	ret = -EIO;
95162306a36Sopenharmony_ci	memset(&op, 0, sizeof(op));
95262306a36Sopenharmony_ci	op.cmd_q = cmd_q;
95362306a36Sopenharmony_ci	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
95462306a36Sopenharmony_ci	op.sb_key = cmd_q->sb_key;
95562306a36Sopenharmony_ci	op.sb_ctx = cmd_q->sb_ctx;
95662306a36Sopenharmony_ci	op.init = (aes->mode == CCP_AES_MODE_ECB) ? 0 : 1;
95762306a36Sopenharmony_ci	op.u.aes.type = aes->type;
95862306a36Sopenharmony_ci	op.u.aes.mode = aes->mode;
95962306a36Sopenharmony_ci	op.u.aes.action = aes->action;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	/* All supported key sizes fit in a single (32-byte) SB entry
96262306a36Sopenharmony_ci	 * and must be in little endian format. Use the 256-bit byte
96362306a36Sopenharmony_ci	 * swap passthru option to convert from big endian to little
96462306a36Sopenharmony_ci	 * endian.
96562306a36Sopenharmony_ci	 */
96662306a36Sopenharmony_ci	ret = ccp_init_dm_workarea(&key, cmd_q,
96762306a36Sopenharmony_ci				   CCP_AES_KEY_SB_COUNT * CCP_SB_BYTES,
96862306a36Sopenharmony_ci				   DMA_TO_DEVICE);
96962306a36Sopenharmony_ci	if (ret)
97062306a36Sopenharmony_ci		return ret;
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	dm_offset = CCP_SB_BYTES - aes->key_len;
97362306a36Sopenharmony_ci	ret = ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len);
97462306a36Sopenharmony_ci	if (ret)
97562306a36Sopenharmony_ci		goto e_key;
97662306a36Sopenharmony_ci	ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
97762306a36Sopenharmony_ci			     CCP_PASSTHRU_BYTESWAP_256BIT);
97862306a36Sopenharmony_ci	if (ret) {
97962306a36Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
98062306a36Sopenharmony_ci		goto e_key;
98162306a36Sopenharmony_ci	}
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	/* The AES context fits in a single (32-byte) SB entry and
98462306a36Sopenharmony_ci	 * must be in little endian format. Use the 256-bit byte swap
98562306a36Sopenharmony_ci	 * passthru option to convert from big endian to little endian.
98662306a36Sopenharmony_ci	 */
98762306a36Sopenharmony_ci	ret = ccp_init_dm_workarea(&ctx, cmd_q,
98862306a36Sopenharmony_ci				   CCP_AES_CTX_SB_COUNT * CCP_SB_BYTES,
98962306a36Sopenharmony_ci				   DMA_BIDIRECTIONAL);
99062306a36Sopenharmony_ci	if (ret)
99162306a36Sopenharmony_ci		goto e_key;
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	if (aes->mode != CCP_AES_MODE_ECB) {
99462306a36Sopenharmony_ci		/* Load the AES context - convert to LE */
99562306a36Sopenharmony_ci		dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
99662306a36Sopenharmony_ci		ret = ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
99762306a36Sopenharmony_ci		if (ret)
99862306a36Sopenharmony_ci			goto e_ctx;
99962306a36Sopenharmony_ci		ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
100062306a36Sopenharmony_ci				     CCP_PASSTHRU_BYTESWAP_256BIT);
100162306a36Sopenharmony_ci		if (ret) {
100262306a36Sopenharmony_ci			cmd->engine_error = cmd_q->cmd_error;
100362306a36Sopenharmony_ci			goto e_ctx;
100462306a36Sopenharmony_ci		}
100562306a36Sopenharmony_ci	}
100662306a36Sopenharmony_ci	switch (aes->mode) {
100762306a36Sopenharmony_ci	case CCP_AES_MODE_CFB: /* CFB128 only */
100862306a36Sopenharmony_ci	case CCP_AES_MODE_CTR:
100962306a36Sopenharmony_ci		op.u.aes.size = AES_BLOCK_SIZE * BITS_PER_BYTE - 1;
101062306a36Sopenharmony_ci		break;
101162306a36Sopenharmony_ci	default:
101262306a36Sopenharmony_ci		op.u.aes.size = 0;
101362306a36Sopenharmony_ci	}
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	/* Prepare the input and output data workareas. For in-place
101662306a36Sopenharmony_ci	 * operations we need to set the dma direction to BIDIRECTIONAL
101762306a36Sopenharmony_ci	 * and copy the src workarea to the dst workarea.
101862306a36Sopenharmony_ci	 */
101962306a36Sopenharmony_ci	if (sg_virt(aes->src) == sg_virt(aes->dst))
102062306a36Sopenharmony_ci		in_place = true;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	ret = ccp_init_data(&src, cmd_q, aes->src, aes->src_len,
102362306a36Sopenharmony_ci			    AES_BLOCK_SIZE,
102462306a36Sopenharmony_ci			    in_place ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE);
102562306a36Sopenharmony_ci	if (ret)
102662306a36Sopenharmony_ci		goto e_ctx;
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	if (in_place) {
102962306a36Sopenharmony_ci		dst = src;
103062306a36Sopenharmony_ci	} else {
103162306a36Sopenharmony_ci		ret = ccp_init_data(&dst, cmd_q, aes->dst, aes->src_len,
103262306a36Sopenharmony_ci				    AES_BLOCK_SIZE, DMA_FROM_DEVICE);
103362306a36Sopenharmony_ci		if (ret)
103462306a36Sopenharmony_ci			goto e_src;
103562306a36Sopenharmony_ci	}
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	/* Send data to the CCP AES engine */
103862306a36Sopenharmony_ci	while (src.sg_wa.bytes_left) {
103962306a36Sopenharmony_ci		ccp_prepare_data(&src, &dst, &op, AES_BLOCK_SIZE, true);
104062306a36Sopenharmony_ci		if (!src.sg_wa.bytes_left) {
104162306a36Sopenharmony_ci			op.eom = 1;
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci			/* Since we don't retrieve the AES context in ECB
104462306a36Sopenharmony_ci			 * mode we have to wait for the operation to complete
104562306a36Sopenharmony_ci			 * on the last piece of data
104662306a36Sopenharmony_ci			 */
104762306a36Sopenharmony_ci			if (aes->mode == CCP_AES_MODE_ECB)
104862306a36Sopenharmony_ci				op.soc = 1;
104962306a36Sopenharmony_ci		}
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci		ret = cmd_q->ccp->vdata->perform->aes(&op);
105262306a36Sopenharmony_ci		if (ret) {
105362306a36Sopenharmony_ci			cmd->engine_error = cmd_q->cmd_error;
105462306a36Sopenharmony_ci			goto e_dst;
105562306a36Sopenharmony_ci		}
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci		ccp_process_data(&src, &dst, &op);
105862306a36Sopenharmony_ci	}
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	if (aes->mode != CCP_AES_MODE_ECB) {
106162306a36Sopenharmony_ci		/* Retrieve the AES context - convert from LE to BE using
106262306a36Sopenharmony_ci		 * 32-byte (256-bit) byteswapping
106362306a36Sopenharmony_ci		 */
106462306a36Sopenharmony_ci		ret = ccp_copy_from_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
106562306a36Sopenharmony_ci				       CCP_PASSTHRU_BYTESWAP_256BIT);
106662306a36Sopenharmony_ci		if (ret) {
106762306a36Sopenharmony_ci			cmd->engine_error = cmd_q->cmd_error;
106862306a36Sopenharmony_ci			goto e_dst;
106962306a36Sopenharmony_ci		}
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci		/* ...but we only need AES_BLOCK_SIZE bytes */
107262306a36Sopenharmony_ci		dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
107362306a36Sopenharmony_ci		ccp_get_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
107462306a36Sopenharmony_ci	}
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_cie_dst:
107762306a36Sopenharmony_ci	if (!in_place)
107862306a36Sopenharmony_ci		ccp_free_data(&dst, cmd_q);
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_cie_src:
108162306a36Sopenharmony_ci	ccp_free_data(&src, cmd_q);
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_cie_ctx:
108462306a36Sopenharmony_ci	ccp_dm_free(&ctx);
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_cie_key:
108762306a36Sopenharmony_ci	ccp_dm_free(&key);
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	return ret;
109062306a36Sopenharmony_ci}
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_cistatic noinline_for_stack int
109362306a36Sopenharmony_ciccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
109462306a36Sopenharmony_ci{
109562306a36Sopenharmony_ci	struct ccp_xts_aes_engine *xts = &cmd->u.xts;
109662306a36Sopenharmony_ci	struct ccp_dm_workarea key, ctx;
109762306a36Sopenharmony_ci	struct ccp_data src, dst;
109862306a36Sopenharmony_ci	struct ccp_op op;
109962306a36Sopenharmony_ci	unsigned int unit_size, dm_offset;
110062306a36Sopenharmony_ci	bool in_place = false;
110162306a36Sopenharmony_ci	unsigned int sb_count;
110262306a36Sopenharmony_ci	enum ccp_aes_type aestype;
110362306a36Sopenharmony_ci	int ret;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	switch (xts->unit_size) {
110662306a36Sopenharmony_ci	case CCP_XTS_AES_UNIT_SIZE_16:
110762306a36Sopenharmony_ci		unit_size = 16;
110862306a36Sopenharmony_ci		break;
110962306a36Sopenharmony_ci	case CCP_XTS_AES_UNIT_SIZE_512:
111062306a36Sopenharmony_ci		unit_size = 512;
111162306a36Sopenharmony_ci		break;
111262306a36Sopenharmony_ci	case CCP_XTS_AES_UNIT_SIZE_1024:
111362306a36Sopenharmony_ci		unit_size = 1024;
111462306a36Sopenharmony_ci		break;
111562306a36Sopenharmony_ci	case CCP_XTS_AES_UNIT_SIZE_2048:
111662306a36Sopenharmony_ci		unit_size = 2048;
111762306a36Sopenharmony_ci		break;
111862306a36Sopenharmony_ci	case CCP_XTS_AES_UNIT_SIZE_4096:
111962306a36Sopenharmony_ci		unit_size = 4096;
112062306a36Sopenharmony_ci		break;
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	default:
112362306a36Sopenharmony_ci		return -EINVAL;
112462306a36Sopenharmony_ci	}
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	if (xts->key_len == AES_KEYSIZE_128)
112762306a36Sopenharmony_ci		aestype = CCP_AES_TYPE_128;
112862306a36Sopenharmony_ci	else if (xts->key_len == AES_KEYSIZE_256)
112962306a36Sopenharmony_ci		aestype = CCP_AES_TYPE_256;
113062306a36Sopenharmony_ci	else
113162306a36Sopenharmony_ci		return -EINVAL;
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	if (!xts->final && (xts->src_len & (AES_BLOCK_SIZE - 1)))
113462306a36Sopenharmony_ci		return -EINVAL;
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	if (xts->iv_len != AES_BLOCK_SIZE)
113762306a36Sopenharmony_ci		return -EINVAL;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	if (!xts->key || !xts->iv || !xts->src || !xts->dst)
114062306a36Sopenharmony_ci		return -EINVAL;
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	BUILD_BUG_ON(CCP_XTS_AES_KEY_SB_COUNT != 1);
114362306a36Sopenharmony_ci	BUILD_BUG_ON(CCP_XTS_AES_CTX_SB_COUNT != 1);
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	ret = -EIO;
114662306a36Sopenharmony_ci	memset(&op, 0, sizeof(op));
114762306a36Sopenharmony_ci	op.cmd_q = cmd_q;
114862306a36Sopenharmony_ci	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
114962306a36Sopenharmony_ci	op.sb_key = cmd_q->sb_key;
115062306a36Sopenharmony_ci	op.sb_ctx = cmd_q->sb_ctx;
115162306a36Sopenharmony_ci	op.init = 1;
115262306a36Sopenharmony_ci	op.u.xts.type = aestype;
115362306a36Sopenharmony_ci	op.u.xts.action = xts->action;
115462306a36Sopenharmony_ci	op.u.xts.unit_size = xts->unit_size;
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	/* A version 3 device only supports 128-bit keys, which fits into a
115762306a36Sopenharmony_ci	 * single SB entry. A version 5 device uses a 512-bit vector, so two
115862306a36Sopenharmony_ci	 * SB entries.
115962306a36Sopenharmony_ci	 */
116062306a36Sopenharmony_ci	if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0))
116162306a36Sopenharmony_ci		sb_count = CCP_XTS_AES_KEY_SB_COUNT;
116262306a36Sopenharmony_ci	else
116362306a36Sopenharmony_ci		sb_count = CCP5_XTS_AES_KEY_SB_COUNT;
116462306a36Sopenharmony_ci	ret = ccp_init_dm_workarea(&key, cmd_q,
116562306a36Sopenharmony_ci				   sb_count * CCP_SB_BYTES,
116662306a36Sopenharmony_ci				   DMA_TO_DEVICE);
116762306a36Sopenharmony_ci	if (ret)
116862306a36Sopenharmony_ci		return ret;
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0)) {
117162306a36Sopenharmony_ci		/* All supported key sizes must be in little endian format.
117262306a36Sopenharmony_ci		 * Use the 256-bit byte swap passthru option to convert from
117362306a36Sopenharmony_ci		 * big endian to little endian.
117462306a36Sopenharmony_ci		 */
117562306a36Sopenharmony_ci		dm_offset = CCP_SB_BYTES - AES_KEYSIZE_128;
117662306a36Sopenharmony_ci		ret = ccp_set_dm_area(&key, dm_offset, xts->key, 0, xts->key_len);
117762306a36Sopenharmony_ci		if (ret)
117862306a36Sopenharmony_ci			goto e_key;
117962306a36Sopenharmony_ci		ret = ccp_set_dm_area(&key, 0, xts->key, xts->key_len, xts->key_len);
118062306a36Sopenharmony_ci		if (ret)
118162306a36Sopenharmony_ci			goto e_key;
118262306a36Sopenharmony_ci	} else {
118362306a36Sopenharmony_ci		/* Version 5 CCPs use a 512-bit space for the key: each portion
118462306a36Sopenharmony_ci		 * occupies 256 bits, or one entire slot, and is zero-padded.
118562306a36Sopenharmony_ci		 */
118662306a36Sopenharmony_ci		unsigned int pad;
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci		dm_offset = CCP_SB_BYTES;
118962306a36Sopenharmony_ci		pad = dm_offset - xts->key_len;
119062306a36Sopenharmony_ci		ret = ccp_set_dm_area(&key, pad, xts->key, 0, xts->key_len);
119162306a36Sopenharmony_ci		if (ret)
119262306a36Sopenharmony_ci			goto e_key;
119362306a36Sopenharmony_ci		ret = ccp_set_dm_area(&key, dm_offset + pad, xts->key,
119462306a36Sopenharmony_ci				      xts->key_len, xts->key_len);
119562306a36Sopenharmony_ci		if (ret)
119662306a36Sopenharmony_ci			goto e_key;
119762306a36Sopenharmony_ci	}
119862306a36Sopenharmony_ci	ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
119962306a36Sopenharmony_ci			     CCP_PASSTHRU_BYTESWAP_256BIT);
120062306a36Sopenharmony_ci	if (ret) {
120162306a36Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
120262306a36Sopenharmony_ci		goto e_key;
120362306a36Sopenharmony_ci	}
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	/* The AES context fits in a single (32-byte) SB entry and
120662306a36Sopenharmony_ci	 * for XTS is already in little endian format so no byte swapping
120762306a36Sopenharmony_ci	 * is needed.
120862306a36Sopenharmony_ci	 */
120962306a36Sopenharmony_ci	ret = ccp_init_dm_workarea(&ctx, cmd_q,
121062306a36Sopenharmony_ci				   CCP_XTS_AES_CTX_SB_COUNT * CCP_SB_BYTES,
121162306a36Sopenharmony_ci				   DMA_BIDIRECTIONAL);
121262306a36Sopenharmony_ci	if (ret)
121362306a36Sopenharmony_ci		goto e_key;
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	ret = ccp_set_dm_area(&ctx, 0, xts->iv, 0, xts->iv_len);
121662306a36Sopenharmony_ci	if (ret)
121762306a36Sopenharmony_ci		goto e_ctx;
121862306a36Sopenharmony_ci	ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
121962306a36Sopenharmony_ci			     CCP_PASSTHRU_BYTESWAP_NOOP);
122062306a36Sopenharmony_ci	if (ret) {
122162306a36Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
122262306a36Sopenharmony_ci		goto e_ctx;
122362306a36Sopenharmony_ci	}
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	/* Prepare the input and output data workareas. For in-place
122662306a36Sopenharmony_ci	 * operations we need to set the dma direction to BIDIRECTIONAL
122762306a36Sopenharmony_ci	 * and copy the src workarea to the dst workarea.
122862306a36Sopenharmony_ci	 */
122962306a36Sopenharmony_ci	if (sg_virt(xts->src) == sg_virt(xts->dst))
123062306a36Sopenharmony_ci		in_place = true;
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	ret = ccp_init_data(&src, cmd_q, xts->src, xts->src_len,
123362306a36Sopenharmony_ci			    unit_size,
123462306a36Sopenharmony_ci			    in_place ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE);
123562306a36Sopenharmony_ci	if (ret)
123662306a36Sopenharmony_ci		goto e_ctx;
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	if (in_place) {
123962306a36Sopenharmony_ci		dst = src;
124062306a36Sopenharmony_ci	} else {
124162306a36Sopenharmony_ci		ret = ccp_init_data(&dst, cmd_q, xts->dst, xts->src_len,
124262306a36Sopenharmony_ci				    unit_size, DMA_FROM_DEVICE);
124362306a36Sopenharmony_ci		if (ret)
124462306a36Sopenharmony_ci			goto e_src;
124562306a36Sopenharmony_ci	}
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	/* Send data to the CCP AES engine */
124862306a36Sopenharmony_ci	while (src.sg_wa.bytes_left) {
124962306a36Sopenharmony_ci		ccp_prepare_data(&src, &dst, &op, unit_size, true);
125062306a36Sopenharmony_ci		if (!src.sg_wa.bytes_left)
125162306a36Sopenharmony_ci			op.eom = 1;
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci		ret = cmd_q->ccp->vdata->perform->xts_aes(&op);
125462306a36Sopenharmony_ci		if (ret) {
125562306a36Sopenharmony_ci			cmd->engine_error = cmd_q->cmd_error;
125662306a36Sopenharmony_ci			goto e_dst;
125762306a36Sopenharmony_ci		}
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci		ccp_process_data(&src, &dst, &op);
126062306a36Sopenharmony_ci	}
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	/* Retrieve the AES context - convert from LE to BE using
126362306a36Sopenharmony_ci	 * 32-byte (256-bit) byteswapping
126462306a36Sopenharmony_ci	 */
126562306a36Sopenharmony_ci	ret = ccp_copy_from_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
126662306a36Sopenharmony_ci			       CCP_PASSTHRU_BYTESWAP_256BIT);
126762306a36Sopenharmony_ci	if (ret) {
126862306a36Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
126962306a36Sopenharmony_ci		goto e_dst;
127062306a36Sopenharmony_ci	}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	/* ...but we only need AES_BLOCK_SIZE bytes */
127362306a36Sopenharmony_ci	dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
127462306a36Sopenharmony_ci	ccp_get_dm_area(&ctx, dm_offset, xts->iv, 0, xts->iv_len);
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_cie_dst:
127762306a36Sopenharmony_ci	if (!in_place)
127862306a36Sopenharmony_ci		ccp_free_data(&dst, cmd_q);
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_cie_src:
128162306a36Sopenharmony_ci	ccp_free_data(&src, cmd_q);
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_cie_ctx:
128462306a36Sopenharmony_ci	ccp_dm_free(&ctx);
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_cie_key:
128762306a36Sopenharmony_ci	ccp_dm_free(&key);
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	return ret;
129062306a36Sopenharmony_ci}
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_cistatic noinline_for_stack int
129362306a36Sopenharmony_ciccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
129462306a36Sopenharmony_ci{
129562306a36Sopenharmony_ci	struct ccp_des3_engine *des3 = &cmd->u.des3;
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci	struct ccp_dm_workarea key, ctx;
129862306a36Sopenharmony_ci	struct ccp_data src, dst;
129962306a36Sopenharmony_ci	struct ccp_op op;
130062306a36Sopenharmony_ci	unsigned int dm_offset;
130162306a36Sopenharmony_ci	unsigned int len_singlekey;
130262306a36Sopenharmony_ci	bool in_place = false;
130362306a36Sopenharmony_ci	int ret;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	/* Error checks */
130662306a36Sopenharmony_ci	if (cmd_q->ccp->vdata->version < CCP_VERSION(5, 0))
130762306a36Sopenharmony_ci		return -EINVAL;
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	if (!cmd_q->ccp->vdata->perform->des3)
131062306a36Sopenharmony_ci		return -EINVAL;
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	if (des3->key_len != DES3_EDE_KEY_SIZE)
131362306a36Sopenharmony_ci		return -EINVAL;
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	if (((des3->mode == CCP_DES3_MODE_ECB) ||
131662306a36Sopenharmony_ci		(des3->mode == CCP_DES3_MODE_CBC)) &&
131762306a36Sopenharmony_ci		(des3->src_len & (DES3_EDE_BLOCK_SIZE - 1)))
131862306a36Sopenharmony_ci		return -EINVAL;
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	if (!des3->key || !des3->src || !des3->dst)
132162306a36Sopenharmony_ci		return -EINVAL;
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	if (des3->mode != CCP_DES3_MODE_ECB) {
132462306a36Sopenharmony_ci		if (des3->iv_len != DES3_EDE_BLOCK_SIZE)
132562306a36Sopenharmony_ci			return -EINVAL;
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci		if (!des3->iv)
132862306a36Sopenharmony_ci			return -EINVAL;
132962306a36Sopenharmony_ci	}
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	/* Zero out all the fields of the command desc */
133262306a36Sopenharmony_ci	memset(&op, 0, sizeof(op));
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	/* Set up the Function field */
133562306a36Sopenharmony_ci	op.cmd_q = cmd_q;
133662306a36Sopenharmony_ci	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
133762306a36Sopenharmony_ci	op.sb_key = cmd_q->sb_key;
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	op.init = (des3->mode == CCP_DES3_MODE_ECB) ? 0 : 1;
134062306a36Sopenharmony_ci	op.u.des3.type = des3->type;
134162306a36Sopenharmony_ci	op.u.des3.mode = des3->mode;
134262306a36Sopenharmony_ci	op.u.des3.action = des3->action;
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	/*
134562306a36Sopenharmony_ci	 * All supported key sizes fit in a single (32-byte) KSB entry and
134662306a36Sopenharmony_ci	 * (like AES) must be in little endian format. Use the 256-bit byte
134762306a36Sopenharmony_ci	 * swap passthru option to convert from big endian to little endian.
134862306a36Sopenharmony_ci	 */
134962306a36Sopenharmony_ci	ret = ccp_init_dm_workarea(&key, cmd_q,
135062306a36Sopenharmony_ci				   CCP_DES3_KEY_SB_COUNT * CCP_SB_BYTES,
135162306a36Sopenharmony_ci				   DMA_TO_DEVICE);
135262306a36Sopenharmony_ci	if (ret)
135362306a36Sopenharmony_ci		return ret;
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	/*
135662306a36Sopenharmony_ci	 * The contents of the key triplet are in the reverse order of what
135762306a36Sopenharmony_ci	 * is required by the engine. Copy the 3 pieces individually to put
135862306a36Sopenharmony_ci	 * them where they belong.
135962306a36Sopenharmony_ci	 */
136062306a36Sopenharmony_ci	dm_offset = CCP_SB_BYTES - des3->key_len; /* Basic offset */
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	len_singlekey = des3->key_len / 3;
136362306a36Sopenharmony_ci	ret = ccp_set_dm_area(&key, dm_offset + 2 * len_singlekey,
136462306a36Sopenharmony_ci			      des3->key, 0, len_singlekey);
136562306a36Sopenharmony_ci	if (ret)
136662306a36Sopenharmony_ci		goto e_key;
136762306a36Sopenharmony_ci	ret = ccp_set_dm_area(&key, dm_offset + len_singlekey,
136862306a36Sopenharmony_ci			      des3->key, len_singlekey, len_singlekey);
136962306a36Sopenharmony_ci	if (ret)
137062306a36Sopenharmony_ci		goto e_key;
137162306a36Sopenharmony_ci	ret = ccp_set_dm_area(&key, dm_offset,
137262306a36Sopenharmony_ci			      des3->key, 2 * len_singlekey, len_singlekey);
137362306a36Sopenharmony_ci	if (ret)
137462306a36Sopenharmony_ci		goto e_key;
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	/* Copy the key to the SB */
137762306a36Sopenharmony_ci	ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
137862306a36Sopenharmony_ci			     CCP_PASSTHRU_BYTESWAP_256BIT);
137962306a36Sopenharmony_ci	if (ret) {
138062306a36Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
138162306a36Sopenharmony_ci		goto e_key;
138262306a36Sopenharmony_ci	}
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	/*
138562306a36Sopenharmony_ci	 * The DES3 context fits in a single (32-byte) KSB entry and
138662306a36Sopenharmony_ci	 * must be in little endian format. Use the 256-bit byte swap
138762306a36Sopenharmony_ci	 * passthru option to convert from big endian to little endian.
138862306a36Sopenharmony_ci	 */
138962306a36Sopenharmony_ci	if (des3->mode != CCP_DES3_MODE_ECB) {
139062306a36Sopenharmony_ci		op.sb_ctx = cmd_q->sb_ctx;
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci		ret = ccp_init_dm_workarea(&ctx, cmd_q,
139362306a36Sopenharmony_ci					   CCP_DES3_CTX_SB_COUNT * CCP_SB_BYTES,
139462306a36Sopenharmony_ci					   DMA_BIDIRECTIONAL);
139562306a36Sopenharmony_ci		if (ret)
139662306a36Sopenharmony_ci			goto e_key;
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci		/* Load the context into the LSB */
139962306a36Sopenharmony_ci		dm_offset = CCP_SB_BYTES - des3->iv_len;
140062306a36Sopenharmony_ci		ret = ccp_set_dm_area(&ctx, dm_offset, des3->iv, 0,
140162306a36Sopenharmony_ci				      des3->iv_len);
140262306a36Sopenharmony_ci		if (ret)
140362306a36Sopenharmony_ci			goto e_ctx;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci		ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
140662306a36Sopenharmony_ci				     CCP_PASSTHRU_BYTESWAP_256BIT);
140762306a36Sopenharmony_ci		if (ret) {
140862306a36Sopenharmony_ci			cmd->engine_error = cmd_q->cmd_error;
140962306a36Sopenharmony_ci			goto e_ctx;
141062306a36Sopenharmony_ci		}
141162306a36Sopenharmony_ci	}
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	/*
141462306a36Sopenharmony_ci	 * Prepare the input and output data workareas. For in-place
141562306a36Sopenharmony_ci	 * operations we need to set the dma direction to BIDIRECTIONAL
141662306a36Sopenharmony_ci	 * and copy the src workarea to the dst workarea.
141762306a36Sopenharmony_ci	 */
141862306a36Sopenharmony_ci	if (sg_virt(des3->src) == sg_virt(des3->dst))
141962306a36Sopenharmony_ci		in_place = true;
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	ret = ccp_init_data(&src, cmd_q, des3->src, des3->src_len,
142262306a36Sopenharmony_ci			DES3_EDE_BLOCK_SIZE,
142362306a36Sopenharmony_ci			in_place ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE);
142462306a36Sopenharmony_ci	if (ret)
142562306a36Sopenharmony_ci		goto e_ctx;
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	if (in_place)
142862306a36Sopenharmony_ci		dst = src;
142962306a36Sopenharmony_ci	else {
143062306a36Sopenharmony_ci		ret = ccp_init_data(&dst, cmd_q, des3->dst, des3->src_len,
143162306a36Sopenharmony_ci				DES3_EDE_BLOCK_SIZE, DMA_FROM_DEVICE);
143262306a36Sopenharmony_ci		if (ret)
143362306a36Sopenharmony_ci			goto e_src;
143462306a36Sopenharmony_ci	}
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	/* Send data to the CCP DES3 engine */
143762306a36Sopenharmony_ci	while (src.sg_wa.bytes_left) {
143862306a36Sopenharmony_ci		ccp_prepare_data(&src, &dst, &op, DES3_EDE_BLOCK_SIZE, true);
143962306a36Sopenharmony_ci		if (!src.sg_wa.bytes_left) {
144062306a36Sopenharmony_ci			op.eom = 1;
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci			/* Since we don't retrieve the context in ECB mode
144362306a36Sopenharmony_ci			 * we have to wait for the operation to complete
144462306a36Sopenharmony_ci			 * on the last piece of data
144562306a36Sopenharmony_ci			 */
144662306a36Sopenharmony_ci			op.soc = 0;
144762306a36Sopenharmony_ci		}
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci		ret = cmd_q->ccp->vdata->perform->des3(&op);
145062306a36Sopenharmony_ci		if (ret) {
145162306a36Sopenharmony_ci			cmd->engine_error = cmd_q->cmd_error;
145262306a36Sopenharmony_ci			goto e_dst;
145362306a36Sopenharmony_ci		}
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci		ccp_process_data(&src, &dst, &op);
145662306a36Sopenharmony_ci	}
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	if (des3->mode != CCP_DES3_MODE_ECB) {
145962306a36Sopenharmony_ci		/* Retrieve the context and make BE */
146062306a36Sopenharmony_ci		ret = ccp_copy_from_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
146162306a36Sopenharmony_ci				       CCP_PASSTHRU_BYTESWAP_256BIT);
146262306a36Sopenharmony_ci		if (ret) {
146362306a36Sopenharmony_ci			cmd->engine_error = cmd_q->cmd_error;
146462306a36Sopenharmony_ci			goto e_dst;
146562306a36Sopenharmony_ci		}
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci		/* ...but we only need the last DES3_EDE_BLOCK_SIZE bytes */
146862306a36Sopenharmony_ci		ccp_get_dm_area(&ctx, dm_offset, des3->iv, 0,
146962306a36Sopenharmony_ci				DES3_EDE_BLOCK_SIZE);
147062306a36Sopenharmony_ci	}
147162306a36Sopenharmony_cie_dst:
147262306a36Sopenharmony_ci	if (!in_place)
147362306a36Sopenharmony_ci		ccp_free_data(&dst, cmd_q);
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_cie_src:
147662306a36Sopenharmony_ci	ccp_free_data(&src, cmd_q);
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_cie_ctx:
147962306a36Sopenharmony_ci	if (des3->mode != CCP_DES3_MODE_ECB)
148062306a36Sopenharmony_ci		ccp_dm_free(&ctx);
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_cie_key:
148362306a36Sopenharmony_ci	ccp_dm_free(&key);
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	return ret;
148662306a36Sopenharmony_ci}
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_cistatic noinline_for_stack int
148962306a36Sopenharmony_ciccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
149062306a36Sopenharmony_ci{
149162306a36Sopenharmony_ci	struct ccp_sha_engine *sha = &cmd->u.sha;
149262306a36Sopenharmony_ci	struct ccp_dm_workarea ctx;
149362306a36Sopenharmony_ci	struct ccp_data src;
149462306a36Sopenharmony_ci	struct ccp_op op;
149562306a36Sopenharmony_ci	unsigned int ioffset, ooffset;
149662306a36Sopenharmony_ci	unsigned int digest_size;
149762306a36Sopenharmony_ci	int sb_count;
149862306a36Sopenharmony_ci	const void *init;
149962306a36Sopenharmony_ci	u64 block_size;
150062306a36Sopenharmony_ci	int ctx_size;
150162306a36Sopenharmony_ci	int ret;
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	switch (sha->type) {
150462306a36Sopenharmony_ci	case CCP_SHA_TYPE_1:
150562306a36Sopenharmony_ci		if (sha->ctx_len < SHA1_DIGEST_SIZE)
150662306a36Sopenharmony_ci			return -EINVAL;
150762306a36Sopenharmony_ci		block_size = SHA1_BLOCK_SIZE;
150862306a36Sopenharmony_ci		break;
150962306a36Sopenharmony_ci	case CCP_SHA_TYPE_224:
151062306a36Sopenharmony_ci		if (sha->ctx_len < SHA224_DIGEST_SIZE)
151162306a36Sopenharmony_ci			return -EINVAL;
151262306a36Sopenharmony_ci		block_size = SHA224_BLOCK_SIZE;
151362306a36Sopenharmony_ci		break;
151462306a36Sopenharmony_ci	case CCP_SHA_TYPE_256:
151562306a36Sopenharmony_ci		if (sha->ctx_len < SHA256_DIGEST_SIZE)
151662306a36Sopenharmony_ci			return -EINVAL;
151762306a36Sopenharmony_ci		block_size = SHA256_BLOCK_SIZE;
151862306a36Sopenharmony_ci		break;
151962306a36Sopenharmony_ci	case CCP_SHA_TYPE_384:
152062306a36Sopenharmony_ci		if (cmd_q->ccp->vdata->version < CCP_VERSION(4, 0)
152162306a36Sopenharmony_ci		    || sha->ctx_len < SHA384_DIGEST_SIZE)
152262306a36Sopenharmony_ci			return -EINVAL;
152362306a36Sopenharmony_ci		block_size = SHA384_BLOCK_SIZE;
152462306a36Sopenharmony_ci		break;
152562306a36Sopenharmony_ci	case CCP_SHA_TYPE_512:
152662306a36Sopenharmony_ci		if (cmd_q->ccp->vdata->version < CCP_VERSION(4, 0)
152762306a36Sopenharmony_ci		    || sha->ctx_len < SHA512_DIGEST_SIZE)
152862306a36Sopenharmony_ci			return -EINVAL;
152962306a36Sopenharmony_ci		block_size = SHA512_BLOCK_SIZE;
153062306a36Sopenharmony_ci		break;
153162306a36Sopenharmony_ci	default:
153262306a36Sopenharmony_ci		return -EINVAL;
153362306a36Sopenharmony_ci	}
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	if (!sha->ctx)
153662306a36Sopenharmony_ci		return -EINVAL;
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci	if (!sha->final && (sha->src_len & (block_size - 1)))
153962306a36Sopenharmony_ci		return -EINVAL;
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	/* The version 3 device can't handle zero-length input */
154262306a36Sopenharmony_ci	if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0)) {
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci		if (!sha->src_len) {
154562306a36Sopenharmony_ci			unsigned int digest_len;
154662306a36Sopenharmony_ci			const u8 *sha_zero;
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci			/* Not final, just return */
154962306a36Sopenharmony_ci			if (!sha->final)
155062306a36Sopenharmony_ci				return 0;
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci			/* CCP can't do a zero length sha operation so the
155362306a36Sopenharmony_ci			 * caller must buffer the data.
155462306a36Sopenharmony_ci			 */
155562306a36Sopenharmony_ci			if (sha->msg_bits)
155662306a36Sopenharmony_ci				return -EINVAL;
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci			/* The CCP cannot perform zero-length sha operations
155962306a36Sopenharmony_ci			 * so the caller is required to buffer data for the
156062306a36Sopenharmony_ci			 * final operation. However, a sha operation for a
156162306a36Sopenharmony_ci			 * message with a total length of zero is valid so
156262306a36Sopenharmony_ci			 * known values are required to supply the result.
156362306a36Sopenharmony_ci			 */
156462306a36Sopenharmony_ci			switch (sha->type) {
156562306a36Sopenharmony_ci			case CCP_SHA_TYPE_1:
156662306a36Sopenharmony_ci				sha_zero = sha1_zero_message_hash;
156762306a36Sopenharmony_ci				digest_len = SHA1_DIGEST_SIZE;
156862306a36Sopenharmony_ci				break;
156962306a36Sopenharmony_ci			case CCP_SHA_TYPE_224:
157062306a36Sopenharmony_ci				sha_zero = sha224_zero_message_hash;
157162306a36Sopenharmony_ci				digest_len = SHA224_DIGEST_SIZE;
157262306a36Sopenharmony_ci				break;
157362306a36Sopenharmony_ci			case CCP_SHA_TYPE_256:
157462306a36Sopenharmony_ci				sha_zero = sha256_zero_message_hash;
157562306a36Sopenharmony_ci				digest_len = SHA256_DIGEST_SIZE;
157662306a36Sopenharmony_ci				break;
157762306a36Sopenharmony_ci			default:
157862306a36Sopenharmony_ci				return -EINVAL;
157962306a36Sopenharmony_ci			}
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci			scatterwalk_map_and_copy((void *)sha_zero, sha->ctx, 0,
158262306a36Sopenharmony_ci						 digest_len, 1);
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci			return 0;
158562306a36Sopenharmony_ci		}
158662306a36Sopenharmony_ci	}
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	/* Set variables used throughout */
158962306a36Sopenharmony_ci	switch (sha->type) {
159062306a36Sopenharmony_ci	case CCP_SHA_TYPE_1:
159162306a36Sopenharmony_ci		digest_size = SHA1_DIGEST_SIZE;
159262306a36Sopenharmony_ci		init = (void *) ccp_sha1_init;
159362306a36Sopenharmony_ci		ctx_size = SHA1_DIGEST_SIZE;
159462306a36Sopenharmony_ci		sb_count = 1;
159562306a36Sopenharmony_ci		if (cmd_q->ccp->vdata->version != CCP_VERSION(3, 0))
159662306a36Sopenharmony_ci			ooffset = ioffset = CCP_SB_BYTES - SHA1_DIGEST_SIZE;
159762306a36Sopenharmony_ci		else
159862306a36Sopenharmony_ci			ooffset = ioffset = 0;
159962306a36Sopenharmony_ci		break;
160062306a36Sopenharmony_ci	case CCP_SHA_TYPE_224:
160162306a36Sopenharmony_ci		digest_size = SHA224_DIGEST_SIZE;
160262306a36Sopenharmony_ci		init = (void *) ccp_sha224_init;
160362306a36Sopenharmony_ci		ctx_size = SHA256_DIGEST_SIZE;
160462306a36Sopenharmony_ci		sb_count = 1;
160562306a36Sopenharmony_ci		ioffset = 0;
160662306a36Sopenharmony_ci		if (cmd_q->ccp->vdata->version != CCP_VERSION(3, 0))
160762306a36Sopenharmony_ci			ooffset = CCP_SB_BYTES - SHA224_DIGEST_SIZE;
160862306a36Sopenharmony_ci		else
160962306a36Sopenharmony_ci			ooffset = 0;
161062306a36Sopenharmony_ci		break;
161162306a36Sopenharmony_ci	case CCP_SHA_TYPE_256:
161262306a36Sopenharmony_ci		digest_size = SHA256_DIGEST_SIZE;
161362306a36Sopenharmony_ci		init = (void *) ccp_sha256_init;
161462306a36Sopenharmony_ci		ctx_size = SHA256_DIGEST_SIZE;
161562306a36Sopenharmony_ci		sb_count = 1;
161662306a36Sopenharmony_ci		ooffset = ioffset = 0;
161762306a36Sopenharmony_ci		break;
161862306a36Sopenharmony_ci	case CCP_SHA_TYPE_384:
161962306a36Sopenharmony_ci		digest_size = SHA384_DIGEST_SIZE;
162062306a36Sopenharmony_ci		init = (void *) ccp_sha384_init;
162162306a36Sopenharmony_ci		ctx_size = SHA512_DIGEST_SIZE;
162262306a36Sopenharmony_ci		sb_count = 2;
162362306a36Sopenharmony_ci		ioffset = 0;
162462306a36Sopenharmony_ci		ooffset = 2 * CCP_SB_BYTES - SHA384_DIGEST_SIZE;
162562306a36Sopenharmony_ci		break;
162662306a36Sopenharmony_ci	case CCP_SHA_TYPE_512:
162762306a36Sopenharmony_ci		digest_size = SHA512_DIGEST_SIZE;
162862306a36Sopenharmony_ci		init = (void *) ccp_sha512_init;
162962306a36Sopenharmony_ci		ctx_size = SHA512_DIGEST_SIZE;
163062306a36Sopenharmony_ci		sb_count = 2;
163162306a36Sopenharmony_ci		ooffset = ioffset = 0;
163262306a36Sopenharmony_ci		break;
163362306a36Sopenharmony_ci	default:
163462306a36Sopenharmony_ci		ret = -EINVAL;
163562306a36Sopenharmony_ci		goto e_data;
163662306a36Sopenharmony_ci	}
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci	/* For zero-length plaintext the src pointer is ignored;
163962306a36Sopenharmony_ci	 * otherwise both parts must be valid
164062306a36Sopenharmony_ci	 */
164162306a36Sopenharmony_ci	if (sha->src_len && !sha->src)
164262306a36Sopenharmony_ci		return -EINVAL;
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci	memset(&op, 0, sizeof(op));
164562306a36Sopenharmony_ci	op.cmd_q = cmd_q;
164662306a36Sopenharmony_ci	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
164762306a36Sopenharmony_ci	op.sb_ctx = cmd_q->sb_ctx; /* Pre-allocated */
164862306a36Sopenharmony_ci	op.u.sha.type = sha->type;
164962306a36Sopenharmony_ci	op.u.sha.msg_bits = sha->msg_bits;
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci	/* For SHA1/224/256 the context fits in a single (32-byte) SB entry;
165262306a36Sopenharmony_ci	 * SHA384/512 require 2 adjacent SB slots, with the right half in the
165362306a36Sopenharmony_ci	 * first slot, and the left half in the second. Each portion must then
165462306a36Sopenharmony_ci	 * be in little endian format: use the 256-bit byte swap option.
165562306a36Sopenharmony_ci	 */
165662306a36Sopenharmony_ci	ret = ccp_init_dm_workarea(&ctx, cmd_q, sb_count * CCP_SB_BYTES,
165762306a36Sopenharmony_ci				   DMA_BIDIRECTIONAL);
165862306a36Sopenharmony_ci	if (ret)
165962306a36Sopenharmony_ci		return ret;
166062306a36Sopenharmony_ci	if (sha->first) {
166162306a36Sopenharmony_ci		switch (sha->type) {
166262306a36Sopenharmony_ci		case CCP_SHA_TYPE_1:
166362306a36Sopenharmony_ci		case CCP_SHA_TYPE_224:
166462306a36Sopenharmony_ci		case CCP_SHA_TYPE_256:
166562306a36Sopenharmony_ci			memcpy(ctx.address + ioffset, init, ctx_size);
166662306a36Sopenharmony_ci			break;
166762306a36Sopenharmony_ci		case CCP_SHA_TYPE_384:
166862306a36Sopenharmony_ci		case CCP_SHA_TYPE_512:
166962306a36Sopenharmony_ci			memcpy(ctx.address + ctx_size / 2, init,
167062306a36Sopenharmony_ci			       ctx_size / 2);
167162306a36Sopenharmony_ci			memcpy(ctx.address, init + ctx_size / 2,
167262306a36Sopenharmony_ci			       ctx_size / 2);
167362306a36Sopenharmony_ci			break;
167462306a36Sopenharmony_ci		default:
167562306a36Sopenharmony_ci			ret = -EINVAL;
167662306a36Sopenharmony_ci			goto e_ctx;
167762306a36Sopenharmony_ci		}
167862306a36Sopenharmony_ci	} else {
167962306a36Sopenharmony_ci		/* Restore the context */
168062306a36Sopenharmony_ci		ret = ccp_set_dm_area(&ctx, 0, sha->ctx, 0,
168162306a36Sopenharmony_ci				      sb_count * CCP_SB_BYTES);
168262306a36Sopenharmony_ci		if (ret)
168362306a36Sopenharmony_ci			goto e_ctx;
168462306a36Sopenharmony_ci	}
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
168762306a36Sopenharmony_ci			     CCP_PASSTHRU_BYTESWAP_256BIT);
168862306a36Sopenharmony_ci	if (ret) {
168962306a36Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
169062306a36Sopenharmony_ci		goto e_ctx;
169162306a36Sopenharmony_ci	}
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci	if (sha->src) {
169462306a36Sopenharmony_ci		/* Send data to the CCP SHA engine; block_size is set above */
169562306a36Sopenharmony_ci		ret = ccp_init_data(&src, cmd_q, sha->src, sha->src_len,
169662306a36Sopenharmony_ci				    block_size, DMA_TO_DEVICE);
169762306a36Sopenharmony_ci		if (ret)
169862306a36Sopenharmony_ci			goto e_ctx;
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci		while (src.sg_wa.bytes_left) {
170162306a36Sopenharmony_ci			ccp_prepare_data(&src, NULL, &op, block_size, false);
170262306a36Sopenharmony_ci			if (sha->final && !src.sg_wa.bytes_left)
170362306a36Sopenharmony_ci				op.eom = 1;
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci			ret = cmd_q->ccp->vdata->perform->sha(&op);
170662306a36Sopenharmony_ci			if (ret) {
170762306a36Sopenharmony_ci				cmd->engine_error = cmd_q->cmd_error;
170862306a36Sopenharmony_ci				goto e_data;
170962306a36Sopenharmony_ci			}
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_ci			ccp_process_data(&src, NULL, &op);
171262306a36Sopenharmony_ci		}
171362306a36Sopenharmony_ci	} else {
171462306a36Sopenharmony_ci		op.eom = 1;
171562306a36Sopenharmony_ci		ret = cmd_q->ccp->vdata->perform->sha(&op);
171662306a36Sopenharmony_ci		if (ret) {
171762306a36Sopenharmony_ci			cmd->engine_error = cmd_q->cmd_error;
171862306a36Sopenharmony_ci			goto e_data;
171962306a36Sopenharmony_ci		}
172062306a36Sopenharmony_ci	}
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci	/* Retrieve the SHA context - convert from LE to BE using
172362306a36Sopenharmony_ci	 * 32-byte (256-bit) byteswapping to BE
172462306a36Sopenharmony_ci	 */
172562306a36Sopenharmony_ci	ret = ccp_copy_from_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
172662306a36Sopenharmony_ci			       CCP_PASSTHRU_BYTESWAP_256BIT);
172762306a36Sopenharmony_ci	if (ret) {
172862306a36Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
172962306a36Sopenharmony_ci		goto e_data;
173062306a36Sopenharmony_ci	}
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	if (sha->final) {
173362306a36Sopenharmony_ci		/* Finishing up, so get the digest */
173462306a36Sopenharmony_ci		switch (sha->type) {
173562306a36Sopenharmony_ci		case CCP_SHA_TYPE_1:
173662306a36Sopenharmony_ci		case CCP_SHA_TYPE_224:
173762306a36Sopenharmony_ci		case CCP_SHA_TYPE_256:
173862306a36Sopenharmony_ci			ccp_get_dm_area(&ctx, ooffset,
173962306a36Sopenharmony_ci					sha->ctx, 0,
174062306a36Sopenharmony_ci					digest_size);
174162306a36Sopenharmony_ci			break;
174262306a36Sopenharmony_ci		case CCP_SHA_TYPE_384:
174362306a36Sopenharmony_ci		case CCP_SHA_TYPE_512:
174462306a36Sopenharmony_ci			ccp_get_dm_area(&ctx, 0,
174562306a36Sopenharmony_ci					sha->ctx, LSB_ITEM_SIZE - ooffset,
174662306a36Sopenharmony_ci					LSB_ITEM_SIZE);
174762306a36Sopenharmony_ci			ccp_get_dm_area(&ctx, LSB_ITEM_SIZE + ooffset,
174862306a36Sopenharmony_ci					sha->ctx, 0,
174962306a36Sopenharmony_ci					LSB_ITEM_SIZE - ooffset);
175062306a36Sopenharmony_ci			break;
175162306a36Sopenharmony_ci		default:
175262306a36Sopenharmony_ci			ret = -EINVAL;
175362306a36Sopenharmony_ci			goto e_data;
175462306a36Sopenharmony_ci		}
175562306a36Sopenharmony_ci	} else {
175662306a36Sopenharmony_ci		/* Stash the context */
175762306a36Sopenharmony_ci		ccp_get_dm_area(&ctx, 0, sha->ctx, 0,
175862306a36Sopenharmony_ci				sb_count * CCP_SB_BYTES);
175962306a36Sopenharmony_ci	}
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci	if (sha->final && sha->opad) {
176262306a36Sopenharmony_ci		/* HMAC operation, recursively perform final SHA */
176362306a36Sopenharmony_ci		struct ccp_cmd hmac_cmd;
176462306a36Sopenharmony_ci		struct scatterlist sg;
176562306a36Sopenharmony_ci		u8 *hmac_buf;
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci		if (sha->opad_len != block_size) {
176862306a36Sopenharmony_ci			ret = -EINVAL;
176962306a36Sopenharmony_ci			goto e_data;
177062306a36Sopenharmony_ci		}
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci		hmac_buf = kmalloc(block_size + digest_size, GFP_KERNEL);
177362306a36Sopenharmony_ci		if (!hmac_buf) {
177462306a36Sopenharmony_ci			ret = -ENOMEM;
177562306a36Sopenharmony_ci			goto e_data;
177662306a36Sopenharmony_ci		}
177762306a36Sopenharmony_ci		sg_init_one(&sg, hmac_buf, block_size + digest_size);
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci		scatterwalk_map_and_copy(hmac_buf, sha->opad, 0, block_size, 0);
178062306a36Sopenharmony_ci		switch (sha->type) {
178162306a36Sopenharmony_ci		case CCP_SHA_TYPE_1:
178262306a36Sopenharmony_ci		case CCP_SHA_TYPE_224:
178362306a36Sopenharmony_ci		case CCP_SHA_TYPE_256:
178462306a36Sopenharmony_ci			memcpy(hmac_buf + block_size,
178562306a36Sopenharmony_ci			       ctx.address + ooffset,
178662306a36Sopenharmony_ci			       digest_size);
178762306a36Sopenharmony_ci			break;
178862306a36Sopenharmony_ci		case CCP_SHA_TYPE_384:
178962306a36Sopenharmony_ci		case CCP_SHA_TYPE_512:
179062306a36Sopenharmony_ci			memcpy(hmac_buf + block_size,
179162306a36Sopenharmony_ci			       ctx.address + LSB_ITEM_SIZE + ooffset,
179262306a36Sopenharmony_ci			       LSB_ITEM_SIZE);
179362306a36Sopenharmony_ci			memcpy(hmac_buf + block_size +
179462306a36Sopenharmony_ci			       (LSB_ITEM_SIZE - ooffset),
179562306a36Sopenharmony_ci			       ctx.address,
179662306a36Sopenharmony_ci			       LSB_ITEM_SIZE);
179762306a36Sopenharmony_ci			break;
179862306a36Sopenharmony_ci		default:
179962306a36Sopenharmony_ci			kfree(hmac_buf);
180062306a36Sopenharmony_ci			ret = -EINVAL;
180162306a36Sopenharmony_ci			goto e_data;
180262306a36Sopenharmony_ci		}
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_ci		memset(&hmac_cmd, 0, sizeof(hmac_cmd));
180562306a36Sopenharmony_ci		hmac_cmd.engine = CCP_ENGINE_SHA;
180662306a36Sopenharmony_ci		hmac_cmd.u.sha.type = sha->type;
180762306a36Sopenharmony_ci		hmac_cmd.u.sha.ctx = sha->ctx;
180862306a36Sopenharmony_ci		hmac_cmd.u.sha.ctx_len = sha->ctx_len;
180962306a36Sopenharmony_ci		hmac_cmd.u.sha.src = &sg;
181062306a36Sopenharmony_ci		hmac_cmd.u.sha.src_len = block_size + digest_size;
181162306a36Sopenharmony_ci		hmac_cmd.u.sha.opad = NULL;
181262306a36Sopenharmony_ci		hmac_cmd.u.sha.opad_len = 0;
181362306a36Sopenharmony_ci		hmac_cmd.u.sha.first = 1;
181462306a36Sopenharmony_ci		hmac_cmd.u.sha.final = 1;
181562306a36Sopenharmony_ci		hmac_cmd.u.sha.msg_bits = (block_size + digest_size) << 3;
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci		ret = ccp_run_sha_cmd(cmd_q, &hmac_cmd);
181862306a36Sopenharmony_ci		if (ret)
181962306a36Sopenharmony_ci			cmd->engine_error = hmac_cmd.engine_error;
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci		kfree(hmac_buf);
182262306a36Sopenharmony_ci	}
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_cie_data:
182562306a36Sopenharmony_ci	if (sha->src)
182662306a36Sopenharmony_ci		ccp_free_data(&src, cmd_q);
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_cie_ctx:
182962306a36Sopenharmony_ci	ccp_dm_free(&ctx);
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci	return ret;
183262306a36Sopenharmony_ci}
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_cistatic noinline_for_stack int
183562306a36Sopenharmony_ciccp_run_rsa_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
183662306a36Sopenharmony_ci{
183762306a36Sopenharmony_ci	struct ccp_rsa_engine *rsa = &cmd->u.rsa;
183862306a36Sopenharmony_ci	struct ccp_dm_workarea exp, src, dst;
183962306a36Sopenharmony_ci	struct ccp_op op;
184062306a36Sopenharmony_ci	unsigned int sb_count, i_len, o_len;
184162306a36Sopenharmony_ci	int ret;
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci	/* Check against the maximum allowable size, in bits */
184462306a36Sopenharmony_ci	if (rsa->key_size > cmd_q->ccp->vdata->rsamax)
184562306a36Sopenharmony_ci		return -EINVAL;
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci	if (!rsa->exp || !rsa->mod || !rsa->src || !rsa->dst)
184862306a36Sopenharmony_ci		return -EINVAL;
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci	memset(&op, 0, sizeof(op));
185162306a36Sopenharmony_ci	op.cmd_q = cmd_q;
185262306a36Sopenharmony_ci	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci	/* The RSA modulus must precede the message being acted upon, so
185562306a36Sopenharmony_ci	 * it must be copied to a DMA area where the message and the
185662306a36Sopenharmony_ci	 * modulus can be concatenated.  Therefore the input buffer
185762306a36Sopenharmony_ci	 * length required is twice the output buffer length (which
185862306a36Sopenharmony_ci	 * must be a multiple of 256-bits).  Compute o_len, i_len in bytes.
185962306a36Sopenharmony_ci	 * Buffer sizes must be a multiple of 32 bytes; rounding up may be
186062306a36Sopenharmony_ci	 * required.
186162306a36Sopenharmony_ci	 */
186262306a36Sopenharmony_ci	o_len = 32 * ((rsa->key_size + 255) / 256);
186362306a36Sopenharmony_ci	i_len = o_len * 2;
186462306a36Sopenharmony_ci
186562306a36Sopenharmony_ci	sb_count = 0;
186662306a36Sopenharmony_ci	if (cmd_q->ccp->vdata->version < CCP_VERSION(5, 0)) {
186762306a36Sopenharmony_ci		/* sb_count is the number of storage block slots required
186862306a36Sopenharmony_ci		 * for the modulus.
186962306a36Sopenharmony_ci		 */
187062306a36Sopenharmony_ci		sb_count = o_len / CCP_SB_BYTES;
187162306a36Sopenharmony_ci		op.sb_key = cmd_q->ccp->vdata->perform->sballoc(cmd_q,
187262306a36Sopenharmony_ci								sb_count);
187362306a36Sopenharmony_ci		if (!op.sb_key)
187462306a36Sopenharmony_ci			return -EIO;
187562306a36Sopenharmony_ci	} else {
187662306a36Sopenharmony_ci		/* A version 5 device allows a modulus size that will not fit
187762306a36Sopenharmony_ci		 * in the LSB, so the command will transfer it from memory.
187862306a36Sopenharmony_ci		 * Set the sb key to the default, even though it's not used.
187962306a36Sopenharmony_ci		 */
188062306a36Sopenharmony_ci		op.sb_key = cmd_q->sb_key;
188162306a36Sopenharmony_ci	}
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci	/* The RSA exponent must be in little endian format. Reverse its
188462306a36Sopenharmony_ci	 * byte order.
188562306a36Sopenharmony_ci	 */
188662306a36Sopenharmony_ci	ret = ccp_init_dm_workarea(&exp, cmd_q, o_len, DMA_TO_DEVICE);
188762306a36Sopenharmony_ci	if (ret)
188862306a36Sopenharmony_ci		goto e_sb;
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci	ret = ccp_reverse_set_dm_area(&exp, 0, rsa->exp, 0, rsa->exp_len);
189162306a36Sopenharmony_ci	if (ret)
189262306a36Sopenharmony_ci		goto e_exp;
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	if (cmd_q->ccp->vdata->version < CCP_VERSION(5, 0)) {
189562306a36Sopenharmony_ci		/* Copy the exponent to the local storage block, using
189662306a36Sopenharmony_ci		 * as many 32-byte blocks as were allocated above. It's
189762306a36Sopenharmony_ci		 * already little endian, so no further change is required.
189862306a36Sopenharmony_ci		 */
189962306a36Sopenharmony_ci		ret = ccp_copy_to_sb(cmd_q, &exp, op.jobid, op.sb_key,
190062306a36Sopenharmony_ci				     CCP_PASSTHRU_BYTESWAP_NOOP);
190162306a36Sopenharmony_ci		if (ret) {
190262306a36Sopenharmony_ci			cmd->engine_error = cmd_q->cmd_error;
190362306a36Sopenharmony_ci			goto e_exp;
190462306a36Sopenharmony_ci		}
190562306a36Sopenharmony_ci	} else {
190662306a36Sopenharmony_ci		/* The exponent can be retrieved from memory via DMA. */
190762306a36Sopenharmony_ci		op.exp.u.dma.address = exp.dma.address;
190862306a36Sopenharmony_ci		op.exp.u.dma.offset = 0;
190962306a36Sopenharmony_ci	}
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci	/* Concatenate the modulus and the message. Both the modulus and
191262306a36Sopenharmony_ci	 * the operands must be in little endian format.  Since the input
191362306a36Sopenharmony_ci	 * is in big endian format it must be converted.
191462306a36Sopenharmony_ci	 */
191562306a36Sopenharmony_ci	ret = ccp_init_dm_workarea(&src, cmd_q, i_len, DMA_TO_DEVICE);
191662306a36Sopenharmony_ci	if (ret)
191762306a36Sopenharmony_ci		goto e_exp;
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_ci	ret = ccp_reverse_set_dm_area(&src, 0, rsa->mod, 0, rsa->mod_len);
192062306a36Sopenharmony_ci	if (ret)
192162306a36Sopenharmony_ci		goto e_src;
192262306a36Sopenharmony_ci	ret = ccp_reverse_set_dm_area(&src, o_len, rsa->src, 0, rsa->src_len);
192362306a36Sopenharmony_ci	if (ret)
192462306a36Sopenharmony_ci		goto e_src;
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ci	/* Prepare the output area for the operation */
192762306a36Sopenharmony_ci	ret = ccp_init_dm_workarea(&dst, cmd_q, o_len, DMA_FROM_DEVICE);
192862306a36Sopenharmony_ci	if (ret)
192962306a36Sopenharmony_ci		goto e_src;
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_ci	op.soc = 1;
193262306a36Sopenharmony_ci	op.src.u.dma.address = src.dma.address;
193362306a36Sopenharmony_ci	op.src.u.dma.offset = 0;
193462306a36Sopenharmony_ci	op.src.u.dma.length = i_len;
193562306a36Sopenharmony_ci	op.dst.u.dma.address = dst.dma.address;
193662306a36Sopenharmony_ci	op.dst.u.dma.offset = 0;
193762306a36Sopenharmony_ci	op.dst.u.dma.length = o_len;
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	op.u.rsa.mod_size = rsa->key_size;
194062306a36Sopenharmony_ci	op.u.rsa.input_len = i_len;
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci	ret = cmd_q->ccp->vdata->perform->rsa(&op);
194362306a36Sopenharmony_ci	if (ret) {
194462306a36Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
194562306a36Sopenharmony_ci		goto e_dst;
194662306a36Sopenharmony_ci	}
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_ci	ccp_reverse_get_dm_area(&dst, 0, rsa->dst, 0, rsa->mod_len);
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_cie_dst:
195162306a36Sopenharmony_ci	ccp_dm_free(&dst);
195262306a36Sopenharmony_ci
195362306a36Sopenharmony_cie_src:
195462306a36Sopenharmony_ci	ccp_dm_free(&src);
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_cie_exp:
195762306a36Sopenharmony_ci	ccp_dm_free(&exp);
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_cie_sb:
196062306a36Sopenharmony_ci	if (sb_count)
196162306a36Sopenharmony_ci		cmd_q->ccp->vdata->perform->sbfree(cmd_q, op.sb_key, sb_count);
196262306a36Sopenharmony_ci
196362306a36Sopenharmony_ci	return ret;
196462306a36Sopenharmony_ci}
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_cistatic noinline_for_stack int
196762306a36Sopenharmony_ciccp_run_passthru_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
196862306a36Sopenharmony_ci{
196962306a36Sopenharmony_ci	struct ccp_passthru_engine *pt = &cmd->u.passthru;
197062306a36Sopenharmony_ci	struct ccp_dm_workarea mask;
197162306a36Sopenharmony_ci	struct ccp_data src, dst;
197262306a36Sopenharmony_ci	struct ccp_op op;
197362306a36Sopenharmony_ci	bool in_place = false;
197462306a36Sopenharmony_ci	unsigned int i;
197562306a36Sopenharmony_ci	int ret = 0;
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci	if (!pt->final && (pt->src_len & (CCP_PASSTHRU_BLOCKSIZE - 1)))
197862306a36Sopenharmony_ci		return -EINVAL;
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci	if (!pt->src || !pt->dst)
198162306a36Sopenharmony_ci		return -EINVAL;
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci	if (pt->bit_mod != CCP_PASSTHRU_BITWISE_NOOP) {
198462306a36Sopenharmony_ci		if (pt->mask_len != CCP_PASSTHRU_MASKSIZE)
198562306a36Sopenharmony_ci			return -EINVAL;
198662306a36Sopenharmony_ci		if (!pt->mask)
198762306a36Sopenharmony_ci			return -EINVAL;
198862306a36Sopenharmony_ci	}
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci	BUILD_BUG_ON(CCP_PASSTHRU_SB_COUNT != 1);
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci	memset(&op, 0, sizeof(op));
199362306a36Sopenharmony_ci	op.cmd_q = cmd_q;
199462306a36Sopenharmony_ci	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	if (pt->bit_mod != CCP_PASSTHRU_BITWISE_NOOP) {
199762306a36Sopenharmony_ci		/* Load the mask */
199862306a36Sopenharmony_ci		op.sb_key = cmd_q->sb_key;
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_ci		ret = ccp_init_dm_workarea(&mask, cmd_q,
200162306a36Sopenharmony_ci					   CCP_PASSTHRU_SB_COUNT *
200262306a36Sopenharmony_ci					   CCP_SB_BYTES,
200362306a36Sopenharmony_ci					   DMA_TO_DEVICE);
200462306a36Sopenharmony_ci		if (ret)
200562306a36Sopenharmony_ci			return ret;
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_ci		ret = ccp_set_dm_area(&mask, 0, pt->mask, 0, pt->mask_len);
200862306a36Sopenharmony_ci		if (ret)
200962306a36Sopenharmony_ci			goto e_mask;
201062306a36Sopenharmony_ci		ret = ccp_copy_to_sb(cmd_q, &mask, op.jobid, op.sb_key,
201162306a36Sopenharmony_ci				     CCP_PASSTHRU_BYTESWAP_NOOP);
201262306a36Sopenharmony_ci		if (ret) {
201362306a36Sopenharmony_ci			cmd->engine_error = cmd_q->cmd_error;
201462306a36Sopenharmony_ci			goto e_mask;
201562306a36Sopenharmony_ci		}
201662306a36Sopenharmony_ci	}
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_ci	/* Prepare the input and output data workareas. For in-place
201962306a36Sopenharmony_ci	 * operations we need to set the dma direction to BIDIRECTIONAL
202062306a36Sopenharmony_ci	 * and copy the src workarea to the dst workarea.
202162306a36Sopenharmony_ci	 */
202262306a36Sopenharmony_ci	if (sg_virt(pt->src) == sg_virt(pt->dst))
202362306a36Sopenharmony_ci		in_place = true;
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_ci	ret = ccp_init_data(&src, cmd_q, pt->src, pt->src_len,
202662306a36Sopenharmony_ci			    CCP_PASSTHRU_MASKSIZE,
202762306a36Sopenharmony_ci			    in_place ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE);
202862306a36Sopenharmony_ci	if (ret)
202962306a36Sopenharmony_ci		goto e_mask;
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci	if (in_place) {
203262306a36Sopenharmony_ci		dst = src;
203362306a36Sopenharmony_ci	} else {
203462306a36Sopenharmony_ci		ret = ccp_init_data(&dst, cmd_q, pt->dst, pt->src_len,
203562306a36Sopenharmony_ci				    CCP_PASSTHRU_MASKSIZE, DMA_FROM_DEVICE);
203662306a36Sopenharmony_ci		if (ret)
203762306a36Sopenharmony_ci			goto e_src;
203862306a36Sopenharmony_ci	}
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci	/* Send data to the CCP Passthru engine
204162306a36Sopenharmony_ci	 *   Because the CCP engine works on a single source and destination
204262306a36Sopenharmony_ci	 *   dma address at a time, each entry in the source scatterlist
204362306a36Sopenharmony_ci	 *   (after the dma_map_sg call) must be less than or equal to the
204462306a36Sopenharmony_ci	 *   (remaining) length in the destination scatterlist entry and the
204562306a36Sopenharmony_ci	 *   length must be a multiple of CCP_PASSTHRU_BLOCKSIZE
204662306a36Sopenharmony_ci	 */
204762306a36Sopenharmony_ci	dst.sg_wa.sg_used = 0;
204862306a36Sopenharmony_ci	for (i = 1; i <= src.sg_wa.dma_count; i++) {
204962306a36Sopenharmony_ci		if (!dst.sg_wa.sg ||
205062306a36Sopenharmony_ci		    (sg_dma_len(dst.sg_wa.sg) < sg_dma_len(src.sg_wa.sg))) {
205162306a36Sopenharmony_ci			ret = -EINVAL;
205262306a36Sopenharmony_ci			goto e_dst;
205362306a36Sopenharmony_ci		}
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci		if (i == src.sg_wa.dma_count) {
205662306a36Sopenharmony_ci			op.eom = 1;
205762306a36Sopenharmony_ci			op.soc = 1;
205862306a36Sopenharmony_ci		}
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ci		op.src.type = CCP_MEMTYPE_SYSTEM;
206162306a36Sopenharmony_ci		op.src.u.dma.address = sg_dma_address(src.sg_wa.sg);
206262306a36Sopenharmony_ci		op.src.u.dma.offset = 0;
206362306a36Sopenharmony_ci		op.src.u.dma.length = sg_dma_len(src.sg_wa.sg);
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci		op.dst.type = CCP_MEMTYPE_SYSTEM;
206662306a36Sopenharmony_ci		op.dst.u.dma.address = sg_dma_address(dst.sg_wa.sg);
206762306a36Sopenharmony_ci		op.dst.u.dma.offset = dst.sg_wa.sg_used;
206862306a36Sopenharmony_ci		op.dst.u.dma.length = op.src.u.dma.length;
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_ci		ret = cmd_q->ccp->vdata->perform->passthru(&op);
207162306a36Sopenharmony_ci		if (ret) {
207262306a36Sopenharmony_ci			cmd->engine_error = cmd_q->cmd_error;
207362306a36Sopenharmony_ci			goto e_dst;
207462306a36Sopenharmony_ci		}
207562306a36Sopenharmony_ci
207662306a36Sopenharmony_ci		dst.sg_wa.sg_used += sg_dma_len(src.sg_wa.sg);
207762306a36Sopenharmony_ci		if (dst.sg_wa.sg_used == sg_dma_len(dst.sg_wa.sg)) {
207862306a36Sopenharmony_ci			dst.sg_wa.sg = sg_next(dst.sg_wa.sg);
207962306a36Sopenharmony_ci			dst.sg_wa.sg_used = 0;
208062306a36Sopenharmony_ci		}
208162306a36Sopenharmony_ci		src.sg_wa.sg = sg_next(src.sg_wa.sg);
208262306a36Sopenharmony_ci	}
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_cie_dst:
208562306a36Sopenharmony_ci	if (!in_place)
208662306a36Sopenharmony_ci		ccp_free_data(&dst, cmd_q);
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_cie_src:
208962306a36Sopenharmony_ci	ccp_free_data(&src, cmd_q);
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_cie_mask:
209262306a36Sopenharmony_ci	if (pt->bit_mod != CCP_PASSTHRU_BITWISE_NOOP)
209362306a36Sopenharmony_ci		ccp_dm_free(&mask);
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci	return ret;
209662306a36Sopenharmony_ci}
209762306a36Sopenharmony_ci
209862306a36Sopenharmony_cistatic noinline_for_stack int
209962306a36Sopenharmony_ciccp_run_passthru_nomap_cmd(struct ccp_cmd_queue *cmd_q,
210062306a36Sopenharmony_ci				      struct ccp_cmd *cmd)
210162306a36Sopenharmony_ci{
210262306a36Sopenharmony_ci	struct ccp_passthru_nomap_engine *pt = &cmd->u.passthru_nomap;
210362306a36Sopenharmony_ci	struct ccp_dm_workarea mask;
210462306a36Sopenharmony_ci	struct ccp_op op;
210562306a36Sopenharmony_ci	int ret;
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_ci	if (!pt->final && (pt->src_len & (CCP_PASSTHRU_BLOCKSIZE - 1)))
210862306a36Sopenharmony_ci		return -EINVAL;
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci	if (!pt->src_dma || !pt->dst_dma)
211162306a36Sopenharmony_ci		return -EINVAL;
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_ci	if (pt->bit_mod != CCP_PASSTHRU_BITWISE_NOOP) {
211462306a36Sopenharmony_ci		if (pt->mask_len != CCP_PASSTHRU_MASKSIZE)
211562306a36Sopenharmony_ci			return -EINVAL;
211662306a36Sopenharmony_ci		if (!pt->mask)
211762306a36Sopenharmony_ci			return -EINVAL;
211862306a36Sopenharmony_ci	}
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci	BUILD_BUG_ON(CCP_PASSTHRU_SB_COUNT != 1);
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_ci	memset(&op, 0, sizeof(op));
212362306a36Sopenharmony_ci	op.cmd_q = cmd_q;
212462306a36Sopenharmony_ci	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	if (pt->bit_mod != CCP_PASSTHRU_BITWISE_NOOP) {
212762306a36Sopenharmony_ci		/* Load the mask */
212862306a36Sopenharmony_ci		op.sb_key = cmd_q->sb_key;
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci		mask.length = pt->mask_len;
213162306a36Sopenharmony_ci		mask.dma.address = pt->mask;
213262306a36Sopenharmony_ci		mask.dma.length = pt->mask_len;
213362306a36Sopenharmony_ci
213462306a36Sopenharmony_ci		ret = ccp_copy_to_sb(cmd_q, &mask, op.jobid, op.sb_key,
213562306a36Sopenharmony_ci				     CCP_PASSTHRU_BYTESWAP_NOOP);
213662306a36Sopenharmony_ci		if (ret) {
213762306a36Sopenharmony_ci			cmd->engine_error = cmd_q->cmd_error;
213862306a36Sopenharmony_ci			return ret;
213962306a36Sopenharmony_ci		}
214062306a36Sopenharmony_ci	}
214162306a36Sopenharmony_ci
214262306a36Sopenharmony_ci	/* Send data to the CCP Passthru engine */
214362306a36Sopenharmony_ci	op.eom = 1;
214462306a36Sopenharmony_ci	op.soc = 1;
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_ci	op.src.type = CCP_MEMTYPE_SYSTEM;
214762306a36Sopenharmony_ci	op.src.u.dma.address = pt->src_dma;
214862306a36Sopenharmony_ci	op.src.u.dma.offset = 0;
214962306a36Sopenharmony_ci	op.src.u.dma.length = pt->src_len;
215062306a36Sopenharmony_ci
215162306a36Sopenharmony_ci	op.dst.type = CCP_MEMTYPE_SYSTEM;
215262306a36Sopenharmony_ci	op.dst.u.dma.address = pt->dst_dma;
215362306a36Sopenharmony_ci	op.dst.u.dma.offset = 0;
215462306a36Sopenharmony_ci	op.dst.u.dma.length = pt->src_len;
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ci	ret = cmd_q->ccp->vdata->perform->passthru(&op);
215762306a36Sopenharmony_ci	if (ret)
215862306a36Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
215962306a36Sopenharmony_ci
216062306a36Sopenharmony_ci	return ret;
216162306a36Sopenharmony_ci}
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_cistatic int ccp_run_ecc_mm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
216462306a36Sopenharmony_ci{
216562306a36Sopenharmony_ci	struct ccp_ecc_engine *ecc = &cmd->u.ecc;
216662306a36Sopenharmony_ci	struct ccp_dm_workarea src, dst;
216762306a36Sopenharmony_ci	struct ccp_op op;
216862306a36Sopenharmony_ci	int ret;
216962306a36Sopenharmony_ci	u8 *save;
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_ci	if (!ecc->u.mm.operand_1 ||
217262306a36Sopenharmony_ci	    (ecc->u.mm.operand_1_len > CCP_ECC_MODULUS_BYTES))
217362306a36Sopenharmony_ci		return -EINVAL;
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci	if (ecc->function != CCP_ECC_FUNCTION_MINV_384BIT)
217662306a36Sopenharmony_ci		if (!ecc->u.mm.operand_2 ||
217762306a36Sopenharmony_ci		    (ecc->u.mm.operand_2_len > CCP_ECC_MODULUS_BYTES))
217862306a36Sopenharmony_ci			return -EINVAL;
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci	if (!ecc->u.mm.result ||
218162306a36Sopenharmony_ci	    (ecc->u.mm.result_len < CCP_ECC_MODULUS_BYTES))
218262306a36Sopenharmony_ci		return -EINVAL;
218362306a36Sopenharmony_ci
218462306a36Sopenharmony_ci	memset(&op, 0, sizeof(op));
218562306a36Sopenharmony_ci	op.cmd_q = cmd_q;
218662306a36Sopenharmony_ci	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ci	/* Concatenate the modulus and the operands. Both the modulus and
218962306a36Sopenharmony_ci	 * the operands must be in little endian format.  Since the input
219062306a36Sopenharmony_ci	 * is in big endian format it must be converted and placed in a
219162306a36Sopenharmony_ci	 * fixed length buffer.
219262306a36Sopenharmony_ci	 */
219362306a36Sopenharmony_ci	ret = ccp_init_dm_workarea(&src, cmd_q, CCP_ECC_SRC_BUF_SIZE,
219462306a36Sopenharmony_ci				   DMA_TO_DEVICE);
219562306a36Sopenharmony_ci	if (ret)
219662306a36Sopenharmony_ci		return ret;
219762306a36Sopenharmony_ci
219862306a36Sopenharmony_ci	/* Save the workarea address since it is updated in order to perform
219962306a36Sopenharmony_ci	 * the concatenation
220062306a36Sopenharmony_ci	 */
220162306a36Sopenharmony_ci	save = src.address;
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_ci	/* Copy the ECC modulus */
220462306a36Sopenharmony_ci	ret = ccp_reverse_set_dm_area(&src, 0, ecc->mod, 0, ecc->mod_len);
220562306a36Sopenharmony_ci	if (ret)
220662306a36Sopenharmony_ci		goto e_src;
220762306a36Sopenharmony_ci	src.address += CCP_ECC_OPERAND_SIZE;
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	/* Copy the first operand */
221062306a36Sopenharmony_ci	ret = ccp_reverse_set_dm_area(&src, 0, ecc->u.mm.operand_1, 0,
221162306a36Sopenharmony_ci				      ecc->u.mm.operand_1_len);
221262306a36Sopenharmony_ci	if (ret)
221362306a36Sopenharmony_ci		goto e_src;
221462306a36Sopenharmony_ci	src.address += CCP_ECC_OPERAND_SIZE;
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_ci	if (ecc->function != CCP_ECC_FUNCTION_MINV_384BIT) {
221762306a36Sopenharmony_ci		/* Copy the second operand */
221862306a36Sopenharmony_ci		ret = ccp_reverse_set_dm_area(&src, 0, ecc->u.mm.operand_2, 0,
221962306a36Sopenharmony_ci					      ecc->u.mm.operand_2_len);
222062306a36Sopenharmony_ci		if (ret)
222162306a36Sopenharmony_ci			goto e_src;
222262306a36Sopenharmony_ci		src.address += CCP_ECC_OPERAND_SIZE;
222362306a36Sopenharmony_ci	}
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci	/* Restore the workarea address */
222662306a36Sopenharmony_ci	src.address = save;
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_ci	/* Prepare the output area for the operation */
222962306a36Sopenharmony_ci	ret = ccp_init_dm_workarea(&dst, cmd_q, CCP_ECC_DST_BUF_SIZE,
223062306a36Sopenharmony_ci				   DMA_FROM_DEVICE);
223162306a36Sopenharmony_ci	if (ret)
223262306a36Sopenharmony_ci		goto e_src;
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci	op.soc = 1;
223562306a36Sopenharmony_ci	op.src.u.dma.address = src.dma.address;
223662306a36Sopenharmony_ci	op.src.u.dma.offset = 0;
223762306a36Sopenharmony_ci	op.src.u.dma.length = src.length;
223862306a36Sopenharmony_ci	op.dst.u.dma.address = dst.dma.address;
223962306a36Sopenharmony_ci	op.dst.u.dma.offset = 0;
224062306a36Sopenharmony_ci	op.dst.u.dma.length = dst.length;
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_ci	op.u.ecc.function = cmd->u.ecc.function;
224362306a36Sopenharmony_ci
224462306a36Sopenharmony_ci	ret = cmd_q->ccp->vdata->perform->ecc(&op);
224562306a36Sopenharmony_ci	if (ret) {
224662306a36Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
224762306a36Sopenharmony_ci		goto e_dst;
224862306a36Sopenharmony_ci	}
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci	ecc->ecc_result = le16_to_cpup(
225162306a36Sopenharmony_ci		(const __le16 *)(dst.address + CCP_ECC_RESULT_OFFSET));
225262306a36Sopenharmony_ci	if (!(ecc->ecc_result & CCP_ECC_RESULT_SUCCESS)) {
225362306a36Sopenharmony_ci		ret = -EIO;
225462306a36Sopenharmony_ci		goto e_dst;
225562306a36Sopenharmony_ci	}
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_ci	/* Save the ECC result */
225862306a36Sopenharmony_ci	ccp_reverse_get_dm_area(&dst, 0, ecc->u.mm.result, 0,
225962306a36Sopenharmony_ci				CCP_ECC_MODULUS_BYTES);
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_cie_dst:
226262306a36Sopenharmony_ci	ccp_dm_free(&dst);
226362306a36Sopenharmony_ci
226462306a36Sopenharmony_cie_src:
226562306a36Sopenharmony_ci	ccp_dm_free(&src);
226662306a36Sopenharmony_ci
226762306a36Sopenharmony_ci	return ret;
226862306a36Sopenharmony_ci}
226962306a36Sopenharmony_ci
227062306a36Sopenharmony_cistatic int ccp_run_ecc_pm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
227162306a36Sopenharmony_ci{
227262306a36Sopenharmony_ci	struct ccp_ecc_engine *ecc = &cmd->u.ecc;
227362306a36Sopenharmony_ci	struct ccp_dm_workarea src, dst;
227462306a36Sopenharmony_ci	struct ccp_op op;
227562306a36Sopenharmony_ci	int ret;
227662306a36Sopenharmony_ci	u8 *save;
227762306a36Sopenharmony_ci
227862306a36Sopenharmony_ci	if (!ecc->u.pm.point_1.x ||
227962306a36Sopenharmony_ci	    (ecc->u.pm.point_1.x_len > CCP_ECC_MODULUS_BYTES) ||
228062306a36Sopenharmony_ci	    !ecc->u.pm.point_1.y ||
228162306a36Sopenharmony_ci	    (ecc->u.pm.point_1.y_len > CCP_ECC_MODULUS_BYTES))
228262306a36Sopenharmony_ci		return -EINVAL;
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_ci	if (ecc->function == CCP_ECC_FUNCTION_PADD_384BIT) {
228562306a36Sopenharmony_ci		if (!ecc->u.pm.point_2.x ||
228662306a36Sopenharmony_ci		    (ecc->u.pm.point_2.x_len > CCP_ECC_MODULUS_BYTES) ||
228762306a36Sopenharmony_ci		    !ecc->u.pm.point_2.y ||
228862306a36Sopenharmony_ci		    (ecc->u.pm.point_2.y_len > CCP_ECC_MODULUS_BYTES))
228962306a36Sopenharmony_ci			return -EINVAL;
229062306a36Sopenharmony_ci	} else {
229162306a36Sopenharmony_ci		if (!ecc->u.pm.domain_a ||
229262306a36Sopenharmony_ci		    (ecc->u.pm.domain_a_len > CCP_ECC_MODULUS_BYTES))
229362306a36Sopenharmony_ci			return -EINVAL;
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_ci		if (ecc->function == CCP_ECC_FUNCTION_PMUL_384BIT)
229662306a36Sopenharmony_ci			if (!ecc->u.pm.scalar ||
229762306a36Sopenharmony_ci			    (ecc->u.pm.scalar_len > CCP_ECC_MODULUS_BYTES))
229862306a36Sopenharmony_ci				return -EINVAL;
229962306a36Sopenharmony_ci	}
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci	if (!ecc->u.pm.result.x ||
230262306a36Sopenharmony_ci	    (ecc->u.pm.result.x_len < CCP_ECC_MODULUS_BYTES) ||
230362306a36Sopenharmony_ci	    !ecc->u.pm.result.y ||
230462306a36Sopenharmony_ci	    (ecc->u.pm.result.y_len < CCP_ECC_MODULUS_BYTES))
230562306a36Sopenharmony_ci		return -EINVAL;
230662306a36Sopenharmony_ci
230762306a36Sopenharmony_ci	memset(&op, 0, sizeof(op));
230862306a36Sopenharmony_ci	op.cmd_q = cmd_q;
230962306a36Sopenharmony_ci	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_ci	/* Concatenate the modulus and the operands. Both the modulus and
231262306a36Sopenharmony_ci	 * the operands must be in little endian format.  Since the input
231362306a36Sopenharmony_ci	 * is in big endian format it must be converted and placed in a
231462306a36Sopenharmony_ci	 * fixed length buffer.
231562306a36Sopenharmony_ci	 */
231662306a36Sopenharmony_ci	ret = ccp_init_dm_workarea(&src, cmd_q, CCP_ECC_SRC_BUF_SIZE,
231762306a36Sopenharmony_ci				   DMA_TO_DEVICE);
231862306a36Sopenharmony_ci	if (ret)
231962306a36Sopenharmony_ci		return ret;
232062306a36Sopenharmony_ci
232162306a36Sopenharmony_ci	/* Save the workarea address since it is updated in order to perform
232262306a36Sopenharmony_ci	 * the concatenation
232362306a36Sopenharmony_ci	 */
232462306a36Sopenharmony_ci	save = src.address;
232562306a36Sopenharmony_ci
232662306a36Sopenharmony_ci	/* Copy the ECC modulus */
232762306a36Sopenharmony_ci	ret = ccp_reverse_set_dm_area(&src, 0, ecc->mod, 0, ecc->mod_len);
232862306a36Sopenharmony_ci	if (ret)
232962306a36Sopenharmony_ci		goto e_src;
233062306a36Sopenharmony_ci	src.address += CCP_ECC_OPERAND_SIZE;
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_ci	/* Copy the first point X and Y coordinate */
233362306a36Sopenharmony_ci	ret = ccp_reverse_set_dm_area(&src, 0, ecc->u.pm.point_1.x, 0,
233462306a36Sopenharmony_ci				      ecc->u.pm.point_1.x_len);
233562306a36Sopenharmony_ci	if (ret)
233662306a36Sopenharmony_ci		goto e_src;
233762306a36Sopenharmony_ci	src.address += CCP_ECC_OPERAND_SIZE;
233862306a36Sopenharmony_ci	ret = ccp_reverse_set_dm_area(&src, 0, ecc->u.pm.point_1.y, 0,
233962306a36Sopenharmony_ci				      ecc->u.pm.point_1.y_len);
234062306a36Sopenharmony_ci	if (ret)
234162306a36Sopenharmony_ci		goto e_src;
234262306a36Sopenharmony_ci	src.address += CCP_ECC_OPERAND_SIZE;
234362306a36Sopenharmony_ci
234462306a36Sopenharmony_ci	/* Set the first point Z coordinate to 1 */
234562306a36Sopenharmony_ci	*src.address = 0x01;
234662306a36Sopenharmony_ci	src.address += CCP_ECC_OPERAND_SIZE;
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_ci	if (ecc->function == CCP_ECC_FUNCTION_PADD_384BIT) {
234962306a36Sopenharmony_ci		/* Copy the second point X and Y coordinate */
235062306a36Sopenharmony_ci		ret = ccp_reverse_set_dm_area(&src, 0, ecc->u.pm.point_2.x, 0,
235162306a36Sopenharmony_ci					      ecc->u.pm.point_2.x_len);
235262306a36Sopenharmony_ci		if (ret)
235362306a36Sopenharmony_ci			goto e_src;
235462306a36Sopenharmony_ci		src.address += CCP_ECC_OPERAND_SIZE;
235562306a36Sopenharmony_ci		ret = ccp_reverse_set_dm_area(&src, 0, ecc->u.pm.point_2.y, 0,
235662306a36Sopenharmony_ci					      ecc->u.pm.point_2.y_len);
235762306a36Sopenharmony_ci		if (ret)
235862306a36Sopenharmony_ci			goto e_src;
235962306a36Sopenharmony_ci		src.address += CCP_ECC_OPERAND_SIZE;
236062306a36Sopenharmony_ci
236162306a36Sopenharmony_ci		/* Set the second point Z coordinate to 1 */
236262306a36Sopenharmony_ci		*src.address = 0x01;
236362306a36Sopenharmony_ci		src.address += CCP_ECC_OPERAND_SIZE;
236462306a36Sopenharmony_ci	} else {
236562306a36Sopenharmony_ci		/* Copy the Domain "a" parameter */
236662306a36Sopenharmony_ci		ret = ccp_reverse_set_dm_area(&src, 0, ecc->u.pm.domain_a, 0,
236762306a36Sopenharmony_ci					      ecc->u.pm.domain_a_len);
236862306a36Sopenharmony_ci		if (ret)
236962306a36Sopenharmony_ci			goto e_src;
237062306a36Sopenharmony_ci		src.address += CCP_ECC_OPERAND_SIZE;
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci		if (ecc->function == CCP_ECC_FUNCTION_PMUL_384BIT) {
237362306a36Sopenharmony_ci			/* Copy the scalar value */
237462306a36Sopenharmony_ci			ret = ccp_reverse_set_dm_area(&src, 0,
237562306a36Sopenharmony_ci						      ecc->u.pm.scalar, 0,
237662306a36Sopenharmony_ci						      ecc->u.pm.scalar_len);
237762306a36Sopenharmony_ci			if (ret)
237862306a36Sopenharmony_ci				goto e_src;
237962306a36Sopenharmony_ci			src.address += CCP_ECC_OPERAND_SIZE;
238062306a36Sopenharmony_ci		}
238162306a36Sopenharmony_ci	}
238262306a36Sopenharmony_ci
238362306a36Sopenharmony_ci	/* Restore the workarea address */
238462306a36Sopenharmony_ci	src.address = save;
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci	/* Prepare the output area for the operation */
238762306a36Sopenharmony_ci	ret = ccp_init_dm_workarea(&dst, cmd_q, CCP_ECC_DST_BUF_SIZE,
238862306a36Sopenharmony_ci				   DMA_FROM_DEVICE);
238962306a36Sopenharmony_ci	if (ret)
239062306a36Sopenharmony_ci		goto e_src;
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_ci	op.soc = 1;
239362306a36Sopenharmony_ci	op.src.u.dma.address = src.dma.address;
239462306a36Sopenharmony_ci	op.src.u.dma.offset = 0;
239562306a36Sopenharmony_ci	op.src.u.dma.length = src.length;
239662306a36Sopenharmony_ci	op.dst.u.dma.address = dst.dma.address;
239762306a36Sopenharmony_ci	op.dst.u.dma.offset = 0;
239862306a36Sopenharmony_ci	op.dst.u.dma.length = dst.length;
239962306a36Sopenharmony_ci
240062306a36Sopenharmony_ci	op.u.ecc.function = cmd->u.ecc.function;
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_ci	ret = cmd_q->ccp->vdata->perform->ecc(&op);
240362306a36Sopenharmony_ci	if (ret) {
240462306a36Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
240562306a36Sopenharmony_ci		goto e_dst;
240662306a36Sopenharmony_ci	}
240762306a36Sopenharmony_ci
240862306a36Sopenharmony_ci	ecc->ecc_result = le16_to_cpup(
240962306a36Sopenharmony_ci		(const __le16 *)(dst.address + CCP_ECC_RESULT_OFFSET));
241062306a36Sopenharmony_ci	if (!(ecc->ecc_result & CCP_ECC_RESULT_SUCCESS)) {
241162306a36Sopenharmony_ci		ret = -EIO;
241262306a36Sopenharmony_ci		goto e_dst;
241362306a36Sopenharmony_ci	}
241462306a36Sopenharmony_ci
241562306a36Sopenharmony_ci	/* Save the workarea address since it is updated as we walk through
241662306a36Sopenharmony_ci	 * to copy the point math result
241762306a36Sopenharmony_ci	 */
241862306a36Sopenharmony_ci	save = dst.address;
241962306a36Sopenharmony_ci
242062306a36Sopenharmony_ci	/* Save the ECC result X and Y coordinates */
242162306a36Sopenharmony_ci	ccp_reverse_get_dm_area(&dst, 0, ecc->u.pm.result.x, 0,
242262306a36Sopenharmony_ci				CCP_ECC_MODULUS_BYTES);
242362306a36Sopenharmony_ci	dst.address += CCP_ECC_OUTPUT_SIZE;
242462306a36Sopenharmony_ci	ccp_reverse_get_dm_area(&dst, 0, ecc->u.pm.result.y, 0,
242562306a36Sopenharmony_ci				CCP_ECC_MODULUS_BYTES);
242662306a36Sopenharmony_ci
242762306a36Sopenharmony_ci	/* Restore the workarea address */
242862306a36Sopenharmony_ci	dst.address = save;
242962306a36Sopenharmony_ci
243062306a36Sopenharmony_cie_dst:
243162306a36Sopenharmony_ci	ccp_dm_free(&dst);
243262306a36Sopenharmony_ci
243362306a36Sopenharmony_cie_src:
243462306a36Sopenharmony_ci	ccp_dm_free(&src);
243562306a36Sopenharmony_ci
243662306a36Sopenharmony_ci	return ret;
243762306a36Sopenharmony_ci}
243862306a36Sopenharmony_ci
243962306a36Sopenharmony_cistatic noinline_for_stack int
244062306a36Sopenharmony_ciccp_run_ecc_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
244162306a36Sopenharmony_ci{
244262306a36Sopenharmony_ci	struct ccp_ecc_engine *ecc = &cmd->u.ecc;
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci	ecc->ecc_result = 0;
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_ci	if (!ecc->mod ||
244762306a36Sopenharmony_ci	    (ecc->mod_len > CCP_ECC_MODULUS_BYTES))
244862306a36Sopenharmony_ci		return -EINVAL;
244962306a36Sopenharmony_ci
245062306a36Sopenharmony_ci	switch (ecc->function) {
245162306a36Sopenharmony_ci	case CCP_ECC_FUNCTION_MMUL_384BIT:
245262306a36Sopenharmony_ci	case CCP_ECC_FUNCTION_MADD_384BIT:
245362306a36Sopenharmony_ci	case CCP_ECC_FUNCTION_MINV_384BIT:
245462306a36Sopenharmony_ci		return ccp_run_ecc_mm_cmd(cmd_q, cmd);
245562306a36Sopenharmony_ci
245662306a36Sopenharmony_ci	case CCP_ECC_FUNCTION_PADD_384BIT:
245762306a36Sopenharmony_ci	case CCP_ECC_FUNCTION_PMUL_384BIT:
245862306a36Sopenharmony_ci	case CCP_ECC_FUNCTION_PDBL_384BIT:
245962306a36Sopenharmony_ci		return ccp_run_ecc_pm_cmd(cmd_q, cmd);
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci	default:
246262306a36Sopenharmony_ci		return -EINVAL;
246362306a36Sopenharmony_ci	}
246462306a36Sopenharmony_ci}
246562306a36Sopenharmony_ci
246662306a36Sopenharmony_ciint ccp_run_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
246762306a36Sopenharmony_ci{
246862306a36Sopenharmony_ci	int ret;
246962306a36Sopenharmony_ci
247062306a36Sopenharmony_ci	cmd->engine_error = 0;
247162306a36Sopenharmony_ci	cmd_q->cmd_error = 0;
247262306a36Sopenharmony_ci	cmd_q->int_rcvd = 0;
247362306a36Sopenharmony_ci	cmd_q->free_slots = cmd_q->ccp->vdata->perform->get_free_slots(cmd_q);
247462306a36Sopenharmony_ci
247562306a36Sopenharmony_ci	switch (cmd->engine) {
247662306a36Sopenharmony_ci	case CCP_ENGINE_AES:
247762306a36Sopenharmony_ci		switch (cmd->u.aes.mode) {
247862306a36Sopenharmony_ci		case CCP_AES_MODE_CMAC:
247962306a36Sopenharmony_ci			ret = ccp_run_aes_cmac_cmd(cmd_q, cmd);
248062306a36Sopenharmony_ci			break;
248162306a36Sopenharmony_ci		case CCP_AES_MODE_GCM:
248262306a36Sopenharmony_ci			ret = ccp_run_aes_gcm_cmd(cmd_q, cmd);
248362306a36Sopenharmony_ci			break;
248462306a36Sopenharmony_ci		default:
248562306a36Sopenharmony_ci			ret = ccp_run_aes_cmd(cmd_q, cmd);
248662306a36Sopenharmony_ci			break;
248762306a36Sopenharmony_ci		}
248862306a36Sopenharmony_ci		break;
248962306a36Sopenharmony_ci	case CCP_ENGINE_XTS_AES_128:
249062306a36Sopenharmony_ci		ret = ccp_run_xts_aes_cmd(cmd_q, cmd);
249162306a36Sopenharmony_ci		break;
249262306a36Sopenharmony_ci	case CCP_ENGINE_DES3:
249362306a36Sopenharmony_ci		ret = ccp_run_des3_cmd(cmd_q, cmd);
249462306a36Sopenharmony_ci		break;
249562306a36Sopenharmony_ci	case CCP_ENGINE_SHA:
249662306a36Sopenharmony_ci		ret = ccp_run_sha_cmd(cmd_q, cmd);
249762306a36Sopenharmony_ci		break;
249862306a36Sopenharmony_ci	case CCP_ENGINE_RSA:
249962306a36Sopenharmony_ci		ret = ccp_run_rsa_cmd(cmd_q, cmd);
250062306a36Sopenharmony_ci		break;
250162306a36Sopenharmony_ci	case CCP_ENGINE_PASSTHRU:
250262306a36Sopenharmony_ci		if (cmd->flags & CCP_CMD_PASSTHRU_NO_DMA_MAP)
250362306a36Sopenharmony_ci			ret = ccp_run_passthru_nomap_cmd(cmd_q, cmd);
250462306a36Sopenharmony_ci		else
250562306a36Sopenharmony_ci			ret = ccp_run_passthru_cmd(cmd_q, cmd);
250662306a36Sopenharmony_ci		break;
250762306a36Sopenharmony_ci	case CCP_ENGINE_ECC:
250862306a36Sopenharmony_ci		ret = ccp_run_ecc_cmd(cmd_q, cmd);
250962306a36Sopenharmony_ci		break;
251062306a36Sopenharmony_ci	default:
251162306a36Sopenharmony_ci		ret = -EINVAL;
251262306a36Sopenharmony_ci	}
251362306a36Sopenharmony_ci
251462306a36Sopenharmony_ci	return ret;
251562306a36Sopenharmony_ci}
2516