18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * AMD Cryptographic Coprocessor (CCP) driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2013-2019 Advanced Micro Devices, Inc.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author: Tom Lendacky <thomas.lendacky@amd.com>
88c2ecf20Sopenharmony_ci * Author: Gary R Hook <gary.hook@amd.com>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/kernel.h>
148c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
158c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h>
168c2ecf20Sopenharmony_ci#include <crypto/des.h>
178c2ecf20Sopenharmony_ci#include <linux/ccp.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include "ccp-dev.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/* SHA initial context values */
228c2ecf20Sopenharmony_cistatic const __be32 ccp_sha1_init[SHA1_DIGEST_SIZE / sizeof(__be32)] = {
238c2ecf20Sopenharmony_ci	cpu_to_be32(SHA1_H0), cpu_to_be32(SHA1_H1),
248c2ecf20Sopenharmony_ci	cpu_to_be32(SHA1_H2), cpu_to_be32(SHA1_H3),
258c2ecf20Sopenharmony_ci	cpu_to_be32(SHA1_H4),
268c2ecf20Sopenharmony_ci};
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic const __be32 ccp_sha224_init[SHA256_DIGEST_SIZE / sizeof(__be32)] = {
298c2ecf20Sopenharmony_ci	cpu_to_be32(SHA224_H0), cpu_to_be32(SHA224_H1),
308c2ecf20Sopenharmony_ci	cpu_to_be32(SHA224_H2), cpu_to_be32(SHA224_H3),
318c2ecf20Sopenharmony_ci	cpu_to_be32(SHA224_H4), cpu_to_be32(SHA224_H5),
328c2ecf20Sopenharmony_ci	cpu_to_be32(SHA224_H6), cpu_to_be32(SHA224_H7),
338c2ecf20Sopenharmony_ci};
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic const __be32 ccp_sha256_init[SHA256_DIGEST_SIZE / sizeof(__be32)] = {
368c2ecf20Sopenharmony_ci	cpu_to_be32(SHA256_H0), cpu_to_be32(SHA256_H1),
378c2ecf20Sopenharmony_ci	cpu_to_be32(SHA256_H2), cpu_to_be32(SHA256_H3),
388c2ecf20Sopenharmony_ci	cpu_to_be32(SHA256_H4), cpu_to_be32(SHA256_H5),
398c2ecf20Sopenharmony_ci	cpu_to_be32(SHA256_H6), cpu_to_be32(SHA256_H7),
408c2ecf20Sopenharmony_ci};
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic const __be64 ccp_sha384_init[SHA512_DIGEST_SIZE / sizeof(__be64)] = {
438c2ecf20Sopenharmony_ci	cpu_to_be64(SHA384_H0), cpu_to_be64(SHA384_H1),
448c2ecf20Sopenharmony_ci	cpu_to_be64(SHA384_H2), cpu_to_be64(SHA384_H3),
458c2ecf20Sopenharmony_ci	cpu_to_be64(SHA384_H4), cpu_to_be64(SHA384_H5),
468c2ecf20Sopenharmony_ci	cpu_to_be64(SHA384_H6), cpu_to_be64(SHA384_H7),
478c2ecf20Sopenharmony_ci};
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic const __be64 ccp_sha512_init[SHA512_DIGEST_SIZE / sizeof(__be64)] = {
508c2ecf20Sopenharmony_ci	cpu_to_be64(SHA512_H0), cpu_to_be64(SHA512_H1),
518c2ecf20Sopenharmony_ci	cpu_to_be64(SHA512_H2), cpu_to_be64(SHA512_H3),
528c2ecf20Sopenharmony_ci	cpu_to_be64(SHA512_H4), cpu_to_be64(SHA512_H5),
538c2ecf20Sopenharmony_ci	cpu_to_be64(SHA512_H6), cpu_to_be64(SHA512_H7),
548c2ecf20Sopenharmony_ci};
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci#define	CCP_NEW_JOBID(ccp)	((ccp->vdata->version == CCP_VERSION(3, 0)) ? \
578c2ecf20Sopenharmony_ci					ccp_gen_jobid(ccp) : 0)
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic u32 ccp_gen_jobid(struct ccp_device *ccp)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	return atomic_inc_return(&ccp->current_id) & CCP_JOBID_MASK;
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic void ccp_sg_free(struct ccp_sg_workarea *wa)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	if (wa->dma_count)
678c2ecf20Sopenharmony_ci		dma_unmap_sg(wa->dma_dev, wa->dma_sg_head, wa->nents, wa->dma_dir);
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	wa->dma_count = 0;
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic int ccp_init_sg_workarea(struct ccp_sg_workarea *wa, struct device *dev,
738c2ecf20Sopenharmony_ci				struct scatterlist *sg, u64 len,
748c2ecf20Sopenharmony_ci				enum dma_data_direction dma_dir)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	memset(wa, 0, sizeof(*wa));
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	wa->sg = sg;
798c2ecf20Sopenharmony_ci	if (!sg)
808c2ecf20Sopenharmony_ci		return 0;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	wa->nents = sg_nents_for_len(sg, len);
838c2ecf20Sopenharmony_ci	if (wa->nents < 0)
848c2ecf20Sopenharmony_ci		return wa->nents;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	wa->bytes_left = len;
878c2ecf20Sopenharmony_ci	wa->sg_used = 0;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	if (len == 0)
908c2ecf20Sopenharmony_ci		return 0;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	if (dma_dir == DMA_NONE)
938c2ecf20Sopenharmony_ci		return 0;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	wa->dma_sg = sg;
968c2ecf20Sopenharmony_ci	wa->dma_sg_head = sg;
978c2ecf20Sopenharmony_ci	wa->dma_dev = dev;
988c2ecf20Sopenharmony_ci	wa->dma_dir = dma_dir;
998c2ecf20Sopenharmony_ci	wa->dma_count = dma_map_sg(dev, sg, wa->nents, dma_dir);
1008c2ecf20Sopenharmony_ci	if (!wa->dma_count)
1018c2ecf20Sopenharmony_ci		return -ENOMEM;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	return 0;
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic void ccp_update_sg_workarea(struct ccp_sg_workarea *wa, unsigned int len)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	unsigned int nbytes = min_t(u64, len, wa->bytes_left);
1098c2ecf20Sopenharmony_ci	unsigned int sg_combined_len = 0;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	if (!wa->sg)
1128c2ecf20Sopenharmony_ci		return;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	wa->sg_used += nbytes;
1158c2ecf20Sopenharmony_ci	wa->bytes_left -= nbytes;
1168c2ecf20Sopenharmony_ci	if (wa->sg_used == sg_dma_len(wa->dma_sg)) {
1178c2ecf20Sopenharmony_ci		/* Advance to the next DMA scatterlist entry */
1188c2ecf20Sopenharmony_ci		wa->dma_sg = sg_next(wa->dma_sg);
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci		/* In the case that the DMA mapped scatterlist has entries
1218c2ecf20Sopenharmony_ci		 * that have been merged, the non-DMA mapped scatterlist
1228c2ecf20Sopenharmony_ci		 * must be advanced multiple times for each merged entry.
1238c2ecf20Sopenharmony_ci		 * This ensures that the current non-DMA mapped entry
1248c2ecf20Sopenharmony_ci		 * corresponds to the current DMA mapped entry.
1258c2ecf20Sopenharmony_ci		 */
1268c2ecf20Sopenharmony_ci		do {
1278c2ecf20Sopenharmony_ci			sg_combined_len += wa->sg->length;
1288c2ecf20Sopenharmony_ci			wa->sg = sg_next(wa->sg);
1298c2ecf20Sopenharmony_ci		} while (wa->sg_used > sg_combined_len);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci		wa->sg_used = 0;
1328c2ecf20Sopenharmony_ci	}
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic void ccp_dm_free(struct ccp_dm_workarea *wa)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	if (wa->length <= CCP_DMAPOOL_MAX_SIZE) {
1388c2ecf20Sopenharmony_ci		if (wa->address)
1398c2ecf20Sopenharmony_ci			dma_pool_free(wa->dma_pool, wa->address,
1408c2ecf20Sopenharmony_ci				      wa->dma.address);
1418c2ecf20Sopenharmony_ci	} else {
1428c2ecf20Sopenharmony_ci		if (wa->dma.address)
1438c2ecf20Sopenharmony_ci			dma_unmap_single(wa->dev, wa->dma.address, wa->length,
1448c2ecf20Sopenharmony_ci					 wa->dma.dir);
1458c2ecf20Sopenharmony_ci		kfree(wa->address);
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	wa->address = NULL;
1498c2ecf20Sopenharmony_ci	wa->dma.address = 0;
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic int ccp_init_dm_workarea(struct ccp_dm_workarea *wa,
1538c2ecf20Sopenharmony_ci				struct ccp_cmd_queue *cmd_q,
1548c2ecf20Sopenharmony_ci				unsigned int len,
1558c2ecf20Sopenharmony_ci				enum dma_data_direction dir)
1568c2ecf20Sopenharmony_ci{
1578c2ecf20Sopenharmony_ci	memset(wa, 0, sizeof(*wa));
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	if (!len)
1608c2ecf20Sopenharmony_ci		return 0;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	wa->dev = cmd_q->ccp->dev;
1638c2ecf20Sopenharmony_ci	wa->length = len;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	if (len <= CCP_DMAPOOL_MAX_SIZE) {
1668c2ecf20Sopenharmony_ci		wa->dma_pool = cmd_q->dma_pool;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci		wa->address = dma_pool_zalloc(wa->dma_pool, GFP_KERNEL,
1698c2ecf20Sopenharmony_ci					     &wa->dma.address);
1708c2ecf20Sopenharmony_ci		if (!wa->address)
1718c2ecf20Sopenharmony_ci			return -ENOMEM;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci		wa->dma.length = CCP_DMAPOOL_MAX_SIZE;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	} else {
1768c2ecf20Sopenharmony_ci		wa->address = kzalloc(len, GFP_KERNEL);
1778c2ecf20Sopenharmony_ci		if (!wa->address)
1788c2ecf20Sopenharmony_ci			return -ENOMEM;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci		wa->dma.address = dma_map_single(wa->dev, wa->address, len,
1818c2ecf20Sopenharmony_ci						 dir);
1828c2ecf20Sopenharmony_ci		if (dma_mapping_error(wa->dev, wa->dma.address)) {
1838c2ecf20Sopenharmony_ci			kfree(wa->address);
1848c2ecf20Sopenharmony_ci			wa->address = NULL;
1858c2ecf20Sopenharmony_ci			return -ENOMEM;
1868c2ecf20Sopenharmony_ci		}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci		wa->dma.length = len;
1898c2ecf20Sopenharmony_ci	}
1908c2ecf20Sopenharmony_ci	wa->dma.dir = dir;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	return 0;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic int ccp_set_dm_area(struct ccp_dm_workarea *wa, unsigned int wa_offset,
1968c2ecf20Sopenharmony_ci			   struct scatterlist *sg, unsigned int sg_offset,
1978c2ecf20Sopenharmony_ci			   unsigned int len)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	WARN_ON(!wa->address);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	if (len > (wa->length - wa_offset))
2028c2ecf20Sopenharmony_ci		return -EINVAL;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	scatterwalk_map_and_copy(wa->address + wa_offset, sg, sg_offset, len,
2058c2ecf20Sopenharmony_ci				 0);
2068c2ecf20Sopenharmony_ci	return 0;
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_cistatic void ccp_get_dm_area(struct ccp_dm_workarea *wa, unsigned int wa_offset,
2108c2ecf20Sopenharmony_ci			    struct scatterlist *sg, unsigned int sg_offset,
2118c2ecf20Sopenharmony_ci			    unsigned int len)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	WARN_ON(!wa->address);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	scatterwalk_map_and_copy(wa->address + wa_offset, sg, sg_offset, len,
2168c2ecf20Sopenharmony_ci				 1);
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_cistatic int ccp_reverse_set_dm_area(struct ccp_dm_workarea *wa,
2208c2ecf20Sopenharmony_ci				   unsigned int wa_offset,
2218c2ecf20Sopenharmony_ci				   struct scatterlist *sg,
2228c2ecf20Sopenharmony_ci				   unsigned int sg_offset,
2238c2ecf20Sopenharmony_ci				   unsigned int len)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	u8 *p, *q;
2268c2ecf20Sopenharmony_ci	int	rc;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	rc = ccp_set_dm_area(wa, wa_offset, sg, sg_offset, len);
2298c2ecf20Sopenharmony_ci	if (rc)
2308c2ecf20Sopenharmony_ci		return rc;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	p = wa->address + wa_offset;
2338c2ecf20Sopenharmony_ci	q = p + len - 1;
2348c2ecf20Sopenharmony_ci	while (p < q) {
2358c2ecf20Sopenharmony_ci		*p = *p ^ *q;
2368c2ecf20Sopenharmony_ci		*q = *p ^ *q;
2378c2ecf20Sopenharmony_ci		*p = *p ^ *q;
2388c2ecf20Sopenharmony_ci		p++;
2398c2ecf20Sopenharmony_ci		q--;
2408c2ecf20Sopenharmony_ci	}
2418c2ecf20Sopenharmony_ci	return 0;
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic void ccp_reverse_get_dm_area(struct ccp_dm_workarea *wa,
2458c2ecf20Sopenharmony_ci				    unsigned int wa_offset,
2468c2ecf20Sopenharmony_ci				    struct scatterlist *sg,
2478c2ecf20Sopenharmony_ci				    unsigned int sg_offset,
2488c2ecf20Sopenharmony_ci				    unsigned int len)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	u8 *p, *q;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	p = wa->address + wa_offset;
2538c2ecf20Sopenharmony_ci	q = p + len - 1;
2548c2ecf20Sopenharmony_ci	while (p < q) {
2558c2ecf20Sopenharmony_ci		*p = *p ^ *q;
2568c2ecf20Sopenharmony_ci		*q = *p ^ *q;
2578c2ecf20Sopenharmony_ci		*p = *p ^ *q;
2588c2ecf20Sopenharmony_ci		p++;
2598c2ecf20Sopenharmony_ci		q--;
2608c2ecf20Sopenharmony_ci	}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	ccp_get_dm_area(wa, wa_offset, sg, sg_offset, len);
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_cistatic void ccp_free_data(struct ccp_data *data, struct ccp_cmd_queue *cmd_q)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	ccp_dm_free(&data->dm_wa);
2688c2ecf20Sopenharmony_ci	ccp_sg_free(&data->sg_wa);
2698c2ecf20Sopenharmony_ci}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_cistatic int ccp_init_data(struct ccp_data *data, struct ccp_cmd_queue *cmd_q,
2728c2ecf20Sopenharmony_ci			 struct scatterlist *sg, u64 sg_len,
2738c2ecf20Sopenharmony_ci			 unsigned int dm_len,
2748c2ecf20Sopenharmony_ci			 enum dma_data_direction dir)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	int ret;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	memset(data, 0, sizeof(*data));
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	ret = ccp_init_sg_workarea(&data->sg_wa, cmd_q->ccp->dev, sg, sg_len,
2818c2ecf20Sopenharmony_ci				   dir);
2828c2ecf20Sopenharmony_ci	if (ret)
2838c2ecf20Sopenharmony_ci		goto e_err;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	ret = ccp_init_dm_workarea(&data->dm_wa, cmd_q, dm_len, dir);
2868c2ecf20Sopenharmony_ci	if (ret)
2878c2ecf20Sopenharmony_ci		goto e_err;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	return 0;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cie_err:
2928c2ecf20Sopenharmony_ci	ccp_free_data(data, cmd_q);
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	return ret;
2958c2ecf20Sopenharmony_ci}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_cistatic unsigned int ccp_queue_buf(struct ccp_data *data, unsigned int from)
2988c2ecf20Sopenharmony_ci{
2998c2ecf20Sopenharmony_ci	struct ccp_sg_workarea *sg_wa = &data->sg_wa;
3008c2ecf20Sopenharmony_ci	struct ccp_dm_workarea *dm_wa = &data->dm_wa;
3018c2ecf20Sopenharmony_ci	unsigned int buf_count, nbytes;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	/* Clear the buffer if setting it */
3048c2ecf20Sopenharmony_ci	if (!from)
3058c2ecf20Sopenharmony_ci		memset(dm_wa->address, 0, dm_wa->length);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	if (!sg_wa->sg)
3088c2ecf20Sopenharmony_ci		return 0;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	/* Perform the copy operation
3118c2ecf20Sopenharmony_ci	 *   nbytes will always be <= UINT_MAX because dm_wa->length is
3128c2ecf20Sopenharmony_ci	 *   an unsigned int
3138c2ecf20Sopenharmony_ci	 */
3148c2ecf20Sopenharmony_ci	nbytes = min_t(u64, sg_wa->bytes_left, dm_wa->length);
3158c2ecf20Sopenharmony_ci	scatterwalk_map_and_copy(dm_wa->address, sg_wa->sg, sg_wa->sg_used,
3168c2ecf20Sopenharmony_ci				 nbytes, from);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	/* Update the structures and generate the count */
3198c2ecf20Sopenharmony_ci	buf_count = 0;
3208c2ecf20Sopenharmony_ci	while (sg_wa->bytes_left && (buf_count < dm_wa->length)) {
3218c2ecf20Sopenharmony_ci		nbytes = min(sg_dma_len(sg_wa->dma_sg) - sg_wa->sg_used,
3228c2ecf20Sopenharmony_ci			     dm_wa->length - buf_count);
3238c2ecf20Sopenharmony_ci		nbytes = min_t(u64, sg_wa->bytes_left, nbytes);
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci		buf_count += nbytes;
3268c2ecf20Sopenharmony_ci		ccp_update_sg_workarea(sg_wa, nbytes);
3278c2ecf20Sopenharmony_ci	}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	return buf_count;
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_cistatic unsigned int ccp_fill_queue_buf(struct ccp_data *data)
3338c2ecf20Sopenharmony_ci{
3348c2ecf20Sopenharmony_ci	return ccp_queue_buf(data, 0);
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_cistatic unsigned int ccp_empty_queue_buf(struct ccp_data *data)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	return ccp_queue_buf(data, 1);
3408c2ecf20Sopenharmony_ci}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_cistatic void ccp_prepare_data(struct ccp_data *src, struct ccp_data *dst,
3438c2ecf20Sopenharmony_ci			     struct ccp_op *op, unsigned int block_size,
3448c2ecf20Sopenharmony_ci			     bool blocksize_op)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	unsigned int sg_src_len, sg_dst_len, op_len;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	/* The CCP can only DMA from/to one address each per operation. This
3498c2ecf20Sopenharmony_ci	 * requires that we find the smallest DMA area between the source
3508c2ecf20Sopenharmony_ci	 * and destination. The resulting len values will always be <= UINT_MAX
3518c2ecf20Sopenharmony_ci	 * because the dma length is an unsigned int.
3528c2ecf20Sopenharmony_ci	 */
3538c2ecf20Sopenharmony_ci	sg_src_len = sg_dma_len(src->sg_wa.dma_sg) - src->sg_wa.sg_used;
3548c2ecf20Sopenharmony_ci	sg_src_len = min_t(u64, src->sg_wa.bytes_left, sg_src_len);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	if (dst) {
3578c2ecf20Sopenharmony_ci		sg_dst_len = sg_dma_len(dst->sg_wa.dma_sg) - dst->sg_wa.sg_used;
3588c2ecf20Sopenharmony_ci		sg_dst_len = min_t(u64, src->sg_wa.bytes_left, sg_dst_len);
3598c2ecf20Sopenharmony_ci		op_len = min(sg_src_len, sg_dst_len);
3608c2ecf20Sopenharmony_ci	} else {
3618c2ecf20Sopenharmony_ci		op_len = sg_src_len;
3628c2ecf20Sopenharmony_ci	}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	/* The data operation length will be at least block_size in length
3658c2ecf20Sopenharmony_ci	 * or the smaller of available sg room remaining for the source or
3668c2ecf20Sopenharmony_ci	 * the destination
3678c2ecf20Sopenharmony_ci	 */
3688c2ecf20Sopenharmony_ci	op_len = max(op_len, block_size);
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	/* Unless we have to buffer data, there's no reason to wait */
3718c2ecf20Sopenharmony_ci	op->soc = 0;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	if (sg_src_len < block_size) {
3748c2ecf20Sopenharmony_ci		/* Not enough data in the sg element, so it
3758c2ecf20Sopenharmony_ci		 * needs to be buffered into a blocksize chunk
3768c2ecf20Sopenharmony_ci		 */
3778c2ecf20Sopenharmony_ci		int cp_len = ccp_fill_queue_buf(src);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci		op->soc = 1;
3808c2ecf20Sopenharmony_ci		op->src.u.dma.address = src->dm_wa.dma.address;
3818c2ecf20Sopenharmony_ci		op->src.u.dma.offset = 0;
3828c2ecf20Sopenharmony_ci		op->src.u.dma.length = (blocksize_op) ? block_size : cp_len;
3838c2ecf20Sopenharmony_ci	} else {
3848c2ecf20Sopenharmony_ci		/* Enough data in the sg element, but we need to
3858c2ecf20Sopenharmony_ci		 * adjust for any previously copied data
3868c2ecf20Sopenharmony_ci		 */
3878c2ecf20Sopenharmony_ci		op->src.u.dma.address = sg_dma_address(src->sg_wa.dma_sg);
3888c2ecf20Sopenharmony_ci		op->src.u.dma.offset = src->sg_wa.sg_used;
3898c2ecf20Sopenharmony_ci		op->src.u.dma.length = op_len & ~(block_size - 1);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci		ccp_update_sg_workarea(&src->sg_wa, op->src.u.dma.length);
3928c2ecf20Sopenharmony_ci	}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	if (dst) {
3958c2ecf20Sopenharmony_ci		if (sg_dst_len < block_size) {
3968c2ecf20Sopenharmony_ci			/* Not enough room in the sg element or we're on the
3978c2ecf20Sopenharmony_ci			 * last piece of data (when using padding), so the
3988c2ecf20Sopenharmony_ci			 * output needs to be buffered into a blocksize chunk
3998c2ecf20Sopenharmony_ci			 */
4008c2ecf20Sopenharmony_ci			op->soc = 1;
4018c2ecf20Sopenharmony_ci			op->dst.u.dma.address = dst->dm_wa.dma.address;
4028c2ecf20Sopenharmony_ci			op->dst.u.dma.offset = 0;
4038c2ecf20Sopenharmony_ci			op->dst.u.dma.length = op->src.u.dma.length;
4048c2ecf20Sopenharmony_ci		} else {
4058c2ecf20Sopenharmony_ci			/* Enough room in the sg element, but we need to
4068c2ecf20Sopenharmony_ci			 * adjust for any previously used area
4078c2ecf20Sopenharmony_ci			 */
4088c2ecf20Sopenharmony_ci			op->dst.u.dma.address = sg_dma_address(dst->sg_wa.dma_sg);
4098c2ecf20Sopenharmony_ci			op->dst.u.dma.offset = dst->sg_wa.sg_used;
4108c2ecf20Sopenharmony_ci			op->dst.u.dma.length = op->src.u.dma.length;
4118c2ecf20Sopenharmony_ci		}
4128c2ecf20Sopenharmony_ci	}
4138c2ecf20Sopenharmony_ci}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_cistatic void ccp_process_data(struct ccp_data *src, struct ccp_data *dst,
4168c2ecf20Sopenharmony_ci			     struct ccp_op *op)
4178c2ecf20Sopenharmony_ci{
4188c2ecf20Sopenharmony_ci	op->init = 0;
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	if (dst) {
4218c2ecf20Sopenharmony_ci		if (op->dst.u.dma.address == dst->dm_wa.dma.address)
4228c2ecf20Sopenharmony_ci			ccp_empty_queue_buf(dst);
4238c2ecf20Sopenharmony_ci		else
4248c2ecf20Sopenharmony_ci			ccp_update_sg_workarea(&dst->sg_wa,
4258c2ecf20Sopenharmony_ci					       op->dst.u.dma.length);
4268c2ecf20Sopenharmony_ci	}
4278c2ecf20Sopenharmony_ci}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_cistatic int ccp_copy_to_from_sb(struct ccp_cmd_queue *cmd_q,
4308c2ecf20Sopenharmony_ci			       struct ccp_dm_workarea *wa, u32 jobid, u32 sb,
4318c2ecf20Sopenharmony_ci			       u32 byte_swap, bool from)
4328c2ecf20Sopenharmony_ci{
4338c2ecf20Sopenharmony_ci	struct ccp_op op;
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	memset(&op, 0, sizeof(op));
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	op.cmd_q = cmd_q;
4388c2ecf20Sopenharmony_ci	op.jobid = jobid;
4398c2ecf20Sopenharmony_ci	op.eom = 1;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	if (from) {
4428c2ecf20Sopenharmony_ci		op.soc = 1;
4438c2ecf20Sopenharmony_ci		op.src.type = CCP_MEMTYPE_SB;
4448c2ecf20Sopenharmony_ci		op.src.u.sb = sb;
4458c2ecf20Sopenharmony_ci		op.dst.type = CCP_MEMTYPE_SYSTEM;
4468c2ecf20Sopenharmony_ci		op.dst.u.dma.address = wa->dma.address;
4478c2ecf20Sopenharmony_ci		op.dst.u.dma.length = wa->length;
4488c2ecf20Sopenharmony_ci	} else {
4498c2ecf20Sopenharmony_ci		op.src.type = CCP_MEMTYPE_SYSTEM;
4508c2ecf20Sopenharmony_ci		op.src.u.dma.address = wa->dma.address;
4518c2ecf20Sopenharmony_ci		op.src.u.dma.length = wa->length;
4528c2ecf20Sopenharmony_ci		op.dst.type = CCP_MEMTYPE_SB;
4538c2ecf20Sopenharmony_ci		op.dst.u.sb = sb;
4548c2ecf20Sopenharmony_ci	}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	op.u.passthru.byte_swap = byte_swap;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	return cmd_q->ccp->vdata->perform->passthru(&op);
4598c2ecf20Sopenharmony_ci}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_cistatic int ccp_copy_to_sb(struct ccp_cmd_queue *cmd_q,
4628c2ecf20Sopenharmony_ci			  struct ccp_dm_workarea *wa, u32 jobid, u32 sb,
4638c2ecf20Sopenharmony_ci			  u32 byte_swap)
4648c2ecf20Sopenharmony_ci{
4658c2ecf20Sopenharmony_ci	return ccp_copy_to_from_sb(cmd_q, wa, jobid, sb, byte_swap, false);
4668c2ecf20Sopenharmony_ci}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_cistatic int ccp_copy_from_sb(struct ccp_cmd_queue *cmd_q,
4698c2ecf20Sopenharmony_ci			    struct ccp_dm_workarea *wa, u32 jobid, u32 sb,
4708c2ecf20Sopenharmony_ci			    u32 byte_swap)
4718c2ecf20Sopenharmony_ci{
4728c2ecf20Sopenharmony_ci	return ccp_copy_to_from_sb(cmd_q, wa, jobid, sb, byte_swap, true);
4738c2ecf20Sopenharmony_ci}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_cistatic noinline_for_stack int
4768c2ecf20Sopenharmony_ciccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
4778c2ecf20Sopenharmony_ci{
4788c2ecf20Sopenharmony_ci	struct ccp_aes_engine *aes = &cmd->u.aes;
4798c2ecf20Sopenharmony_ci	struct ccp_dm_workarea key, ctx;
4808c2ecf20Sopenharmony_ci	struct ccp_data src;
4818c2ecf20Sopenharmony_ci	struct ccp_op op;
4828c2ecf20Sopenharmony_ci	unsigned int dm_offset;
4838c2ecf20Sopenharmony_ci	int ret;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	if (!((aes->key_len == AES_KEYSIZE_128) ||
4868c2ecf20Sopenharmony_ci	      (aes->key_len == AES_KEYSIZE_192) ||
4878c2ecf20Sopenharmony_ci	      (aes->key_len == AES_KEYSIZE_256)))
4888c2ecf20Sopenharmony_ci		return -EINVAL;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	if (aes->src_len & (AES_BLOCK_SIZE - 1))
4918c2ecf20Sopenharmony_ci		return -EINVAL;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	if (aes->iv_len != AES_BLOCK_SIZE)
4948c2ecf20Sopenharmony_ci		return -EINVAL;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	if (!aes->key || !aes->iv || !aes->src)
4978c2ecf20Sopenharmony_ci		return -EINVAL;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	if (aes->cmac_final) {
5008c2ecf20Sopenharmony_ci		if (aes->cmac_key_len != AES_BLOCK_SIZE)
5018c2ecf20Sopenharmony_ci			return -EINVAL;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci		if (!aes->cmac_key)
5048c2ecf20Sopenharmony_ci			return -EINVAL;
5058c2ecf20Sopenharmony_ci	}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	BUILD_BUG_ON(CCP_AES_KEY_SB_COUNT != 1);
5088c2ecf20Sopenharmony_ci	BUILD_BUG_ON(CCP_AES_CTX_SB_COUNT != 1);
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	ret = -EIO;
5118c2ecf20Sopenharmony_ci	memset(&op, 0, sizeof(op));
5128c2ecf20Sopenharmony_ci	op.cmd_q = cmd_q;
5138c2ecf20Sopenharmony_ci	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
5148c2ecf20Sopenharmony_ci	op.sb_key = cmd_q->sb_key;
5158c2ecf20Sopenharmony_ci	op.sb_ctx = cmd_q->sb_ctx;
5168c2ecf20Sopenharmony_ci	op.init = 1;
5178c2ecf20Sopenharmony_ci	op.u.aes.type = aes->type;
5188c2ecf20Sopenharmony_ci	op.u.aes.mode = aes->mode;
5198c2ecf20Sopenharmony_ci	op.u.aes.action = aes->action;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	/* All supported key sizes fit in a single (32-byte) SB entry
5228c2ecf20Sopenharmony_ci	 * and must be in little endian format. Use the 256-bit byte
5238c2ecf20Sopenharmony_ci	 * swap passthru option to convert from big endian to little
5248c2ecf20Sopenharmony_ci	 * endian.
5258c2ecf20Sopenharmony_ci	 */
5268c2ecf20Sopenharmony_ci	ret = ccp_init_dm_workarea(&key, cmd_q,
5278c2ecf20Sopenharmony_ci				   CCP_AES_KEY_SB_COUNT * CCP_SB_BYTES,
5288c2ecf20Sopenharmony_ci				   DMA_TO_DEVICE);
5298c2ecf20Sopenharmony_ci	if (ret)
5308c2ecf20Sopenharmony_ci		return ret;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	dm_offset = CCP_SB_BYTES - aes->key_len;
5338c2ecf20Sopenharmony_ci	ret = ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len);
5348c2ecf20Sopenharmony_ci	if (ret)
5358c2ecf20Sopenharmony_ci		goto e_key;
5368c2ecf20Sopenharmony_ci	ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
5378c2ecf20Sopenharmony_ci			     CCP_PASSTHRU_BYTESWAP_256BIT);
5388c2ecf20Sopenharmony_ci	if (ret) {
5398c2ecf20Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
5408c2ecf20Sopenharmony_ci		goto e_key;
5418c2ecf20Sopenharmony_ci	}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	/* The AES context fits in a single (32-byte) SB entry and
5448c2ecf20Sopenharmony_ci	 * must be in little endian format. Use the 256-bit byte swap
5458c2ecf20Sopenharmony_ci	 * passthru option to convert from big endian to little endian.
5468c2ecf20Sopenharmony_ci	 */
5478c2ecf20Sopenharmony_ci	ret = ccp_init_dm_workarea(&ctx, cmd_q,
5488c2ecf20Sopenharmony_ci				   CCP_AES_CTX_SB_COUNT * CCP_SB_BYTES,
5498c2ecf20Sopenharmony_ci				   DMA_BIDIRECTIONAL);
5508c2ecf20Sopenharmony_ci	if (ret)
5518c2ecf20Sopenharmony_ci		goto e_key;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
5548c2ecf20Sopenharmony_ci	ret = ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
5558c2ecf20Sopenharmony_ci	if (ret)
5568c2ecf20Sopenharmony_ci		goto e_ctx;
5578c2ecf20Sopenharmony_ci	ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
5588c2ecf20Sopenharmony_ci			     CCP_PASSTHRU_BYTESWAP_256BIT);
5598c2ecf20Sopenharmony_ci	if (ret) {
5608c2ecf20Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
5618c2ecf20Sopenharmony_ci		goto e_ctx;
5628c2ecf20Sopenharmony_ci	}
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	/* Send data to the CCP AES engine */
5658c2ecf20Sopenharmony_ci	ret = ccp_init_data(&src, cmd_q, aes->src, aes->src_len,
5668c2ecf20Sopenharmony_ci			    AES_BLOCK_SIZE, DMA_TO_DEVICE);
5678c2ecf20Sopenharmony_ci	if (ret)
5688c2ecf20Sopenharmony_ci		goto e_ctx;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	while (src.sg_wa.bytes_left) {
5718c2ecf20Sopenharmony_ci		ccp_prepare_data(&src, NULL, &op, AES_BLOCK_SIZE, true);
5728c2ecf20Sopenharmony_ci		if (aes->cmac_final && !src.sg_wa.bytes_left) {
5738c2ecf20Sopenharmony_ci			op.eom = 1;
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci			/* Push the K1/K2 key to the CCP now */
5768c2ecf20Sopenharmony_ci			ret = ccp_copy_from_sb(cmd_q, &ctx, op.jobid,
5778c2ecf20Sopenharmony_ci					       op.sb_ctx,
5788c2ecf20Sopenharmony_ci					       CCP_PASSTHRU_BYTESWAP_256BIT);
5798c2ecf20Sopenharmony_ci			if (ret) {
5808c2ecf20Sopenharmony_ci				cmd->engine_error = cmd_q->cmd_error;
5818c2ecf20Sopenharmony_ci				goto e_src;
5828c2ecf20Sopenharmony_ci			}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci			ret = ccp_set_dm_area(&ctx, 0, aes->cmac_key, 0,
5858c2ecf20Sopenharmony_ci					      aes->cmac_key_len);
5868c2ecf20Sopenharmony_ci			if (ret)
5878c2ecf20Sopenharmony_ci				goto e_src;
5888c2ecf20Sopenharmony_ci			ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
5898c2ecf20Sopenharmony_ci					     CCP_PASSTHRU_BYTESWAP_256BIT);
5908c2ecf20Sopenharmony_ci			if (ret) {
5918c2ecf20Sopenharmony_ci				cmd->engine_error = cmd_q->cmd_error;
5928c2ecf20Sopenharmony_ci				goto e_src;
5938c2ecf20Sopenharmony_ci			}
5948c2ecf20Sopenharmony_ci		}
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci		ret = cmd_q->ccp->vdata->perform->aes(&op);
5978c2ecf20Sopenharmony_ci		if (ret) {
5988c2ecf20Sopenharmony_ci			cmd->engine_error = cmd_q->cmd_error;
5998c2ecf20Sopenharmony_ci			goto e_src;
6008c2ecf20Sopenharmony_ci		}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci		ccp_process_data(&src, NULL, &op);
6038c2ecf20Sopenharmony_ci	}
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	/* Retrieve the AES context - convert from LE to BE using
6068c2ecf20Sopenharmony_ci	 * 32-byte (256-bit) byteswapping
6078c2ecf20Sopenharmony_ci	 */
6088c2ecf20Sopenharmony_ci	ret = ccp_copy_from_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
6098c2ecf20Sopenharmony_ci			       CCP_PASSTHRU_BYTESWAP_256BIT);
6108c2ecf20Sopenharmony_ci	if (ret) {
6118c2ecf20Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
6128c2ecf20Sopenharmony_ci		goto e_src;
6138c2ecf20Sopenharmony_ci	}
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	/* ...but we only need AES_BLOCK_SIZE bytes */
6168c2ecf20Sopenharmony_ci	dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
6178c2ecf20Sopenharmony_ci	ccp_get_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_cie_src:
6208c2ecf20Sopenharmony_ci	ccp_free_data(&src, cmd_q);
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_cie_ctx:
6238c2ecf20Sopenharmony_ci	ccp_dm_free(&ctx);
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_cie_key:
6268c2ecf20Sopenharmony_ci	ccp_dm_free(&key);
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	return ret;
6298c2ecf20Sopenharmony_ci}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_cistatic noinline_for_stack int
6328c2ecf20Sopenharmony_ciccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
6338c2ecf20Sopenharmony_ci{
6348c2ecf20Sopenharmony_ci	struct ccp_aes_engine *aes = &cmd->u.aes;
6358c2ecf20Sopenharmony_ci	struct ccp_dm_workarea key, ctx, final_wa, tag;
6368c2ecf20Sopenharmony_ci	struct ccp_data src, dst;
6378c2ecf20Sopenharmony_ci	struct ccp_data aad;
6388c2ecf20Sopenharmony_ci	struct ccp_op op;
6398c2ecf20Sopenharmony_ci	unsigned int dm_offset;
6408c2ecf20Sopenharmony_ci	unsigned int authsize;
6418c2ecf20Sopenharmony_ci	unsigned int jobid;
6428c2ecf20Sopenharmony_ci	unsigned int ilen;
6438c2ecf20Sopenharmony_ci	bool in_place = true; /* Default value */
6448c2ecf20Sopenharmony_ci	__be64 *final;
6458c2ecf20Sopenharmony_ci	int ret;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	struct scatterlist *p_inp, sg_inp[2];
6488c2ecf20Sopenharmony_ci	struct scatterlist *p_tag, sg_tag[2];
6498c2ecf20Sopenharmony_ci	struct scatterlist *p_outp, sg_outp[2];
6508c2ecf20Sopenharmony_ci	struct scatterlist *p_aad;
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	if (!aes->iv)
6538c2ecf20Sopenharmony_ci		return -EINVAL;
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	if (!((aes->key_len == AES_KEYSIZE_128) ||
6568c2ecf20Sopenharmony_ci		(aes->key_len == AES_KEYSIZE_192) ||
6578c2ecf20Sopenharmony_ci		(aes->key_len == AES_KEYSIZE_256)))
6588c2ecf20Sopenharmony_ci		return -EINVAL;
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	if (!aes->key) /* Gotta have a key SGL */
6618c2ecf20Sopenharmony_ci		return -EINVAL;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	/* Zero defaults to 16 bytes, the maximum size */
6648c2ecf20Sopenharmony_ci	authsize = aes->authsize ? aes->authsize : AES_BLOCK_SIZE;
6658c2ecf20Sopenharmony_ci	switch (authsize) {
6668c2ecf20Sopenharmony_ci	case 16:
6678c2ecf20Sopenharmony_ci	case 15:
6688c2ecf20Sopenharmony_ci	case 14:
6698c2ecf20Sopenharmony_ci	case 13:
6708c2ecf20Sopenharmony_ci	case 12:
6718c2ecf20Sopenharmony_ci	case 8:
6728c2ecf20Sopenharmony_ci	case 4:
6738c2ecf20Sopenharmony_ci		break;
6748c2ecf20Sopenharmony_ci	default:
6758c2ecf20Sopenharmony_ci		return -EINVAL;
6768c2ecf20Sopenharmony_ci	}
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	/* First, decompose the source buffer into AAD & PT,
6798c2ecf20Sopenharmony_ci	 * and the destination buffer into AAD, CT & tag, or
6808c2ecf20Sopenharmony_ci	 * the input into CT & tag.
6818c2ecf20Sopenharmony_ci	 * It is expected that the input and output SGs will
6828c2ecf20Sopenharmony_ci	 * be valid, even if the AAD and input lengths are 0.
6838c2ecf20Sopenharmony_ci	 */
6848c2ecf20Sopenharmony_ci	p_aad = aes->src;
6858c2ecf20Sopenharmony_ci	p_inp = scatterwalk_ffwd(sg_inp, aes->src, aes->aad_len);
6868c2ecf20Sopenharmony_ci	p_outp = scatterwalk_ffwd(sg_outp, aes->dst, aes->aad_len);
6878c2ecf20Sopenharmony_ci	if (aes->action == CCP_AES_ACTION_ENCRYPT) {
6888c2ecf20Sopenharmony_ci		ilen = aes->src_len;
6898c2ecf20Sopenharmony_ci		p_tag = scatterwalk_ffwd(sg_tag, p_outp, ilen);
6908c2ecf20Sopenharmony_ci	} else {
6918c2ecf20Sopenharmony_ci		/* Input length for decryption includes tag */
6928c2ecf20Sopenharmony_ci		ilen = aes->src_len - authsize;
6938c2ecf20Sopenharmony_ci		p_tag = scatterwalk_ffwd(sg_tag, p_inp, ilen);
6948c2ecf20Sopenharmony_ci	}
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	jobid = CCP_NEW_JOBID(cmd_q->ccp);
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	memset(&op, 0, sizeof(op));
6998c2ecf20Sopenharmony_ci	op.cmd_q = cmd_q;
7008c2ecf20Sopenharmony_ci	op.jobid = jobid;
7018c2ecf20Sopenharmony_ci	op.sb_key = cmd_q->sb_key; /* Pre-allocated */
7028c2ecf20Sopenharmony_ci	op.sb_ctx = cmd_q->sb_ctx; /* Pre-allocated */
7038c2ecf20Sopenharmony_ci	op.init = 1;
7048c2ecf20Sopenharmony_ci	op.u.aes.type = aes->type;
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	/* Copy the key to the LSB */
7078c2ecf20Sopenharmony_ci	ret = ccp_init_dm_workarea(&key, cmd_q,
7088c2ecf20Sopenharmony_ci				   CCP_AES_CTX_SB_COUNT * CCP_SB_BYTES,
7098c2ecf20Sopenharmony_ci				   DMA_TO_DEVICE);
7108c2ecf20Sopenharmony_ci	if (ret)
7118c2ecf20Sopenharmony_ci		return ret;
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	dm_offset = CCP_SB_BYTES - aes->key_len;
7148c2ecf20Sopenharmony_ci	ret = ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len);
7158c2ecf20Sopenharmony_ci	if (ret)
7168c2ecf20Sopenharmony_ci		goto e_key;
7178c2ecf20Sopenharmony_ci	ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
7188c2ecf20Sopenharmony_ci			     CCP_PASSTHRU_BYTESWAP_256BIT);
7198c2ecf20Sopenharmony_ci	if (ret) {
7208c2ecf20Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
7218c2ecf20Sopenharmony_ci		goto e_key;
7228c2ecf20Sopenharmony_ci	}
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	/* Copy the context (IV) to the LSB.
7258c2ecf20Sopenharmony_ci	 * There is an assumption here that the IV is 96 bits in length, plus
7268c2ecf20Sopenharmony_ci	 * a nonce of 32 bits. If no IV is present, use a zeroed buffer.
7278c2ecf20Sopenharmony_ci	 */
7288c2ecf20Sopenharmony_ci	ret = ccp_init_dm_workarea(&ctx, cmd_q,
7298c2ecf20Sopenharmony_ci				   CCP_AES_CTX_SB_COUNT * CCP_SB_BYTES,
7308c2ecf20Sopenharmony_ci				   DMA_BIDIRECTIONAL);
7318c2ecf20Sopenharmony_ci	if (ret)
7328c2ecf20Sopenharmony_ci		goto e_key;
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	dm_offset = CCP_AES_CTX_SB_COUNT * CCP_SB_BYTES - aes->iv_len;
7358c2ecf20Sopenharmony_ci	ret = ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
7368c2ecf20Sopenharmony_ci	if (ret)
7378c2ecf20Sopenharmony_ci		goto e_ctx;
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
7408c2ecf20Sopenharmony_ci			     CCP_PASSTHRU_BYTESWAP_256BIT);
7418c2ecf20Sopenharmony_ci	if (ret) {
7428c2ecf20Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
7438c2ecf20Sopenharmony_ci		goto e_ctx;
7448c2ecf20Sopenharmony_ci	}
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	op.init = 1;
7478c2ecf20Sopenharmony_ci	if (aes->aad_len > 0) {
7488c2ecf20Sopenharmony_ci		/* Step 1: Run a GHASH over the Additional Authenticated Data */
7498c2ecf20Sopenharmony_ci		ret = ccp_init_data(&aad, cmd_q, p_aad, aes->aad_len,
7508c2ecf20Sopenharmony_ci				    AES_BLOCK_SIZE,
7518c2ecf20Sopenharmony_ci				    DMA_TO_DEVICE);
7528c2ecf20Sopenharmony_ci		if (ret)
7538c2ecf20Sopenharmony_ci			goto e_ctx;
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci		op.u.aes.mode = CCP_AES_MODE_GHASH;
7568c2ecf20Sopenharmony_ci		op.u.aes.action = CCP_AES_GHASHAAD;
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci		while (aad.sg_wa.bytes_left) {
7598c2ecf20Sopenharmony_ci			ccp_prepare_data(&aad, NULL, &op, AES_BLOCK_SIZE, true);
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci			ret = cmd_q->ccp->vdata->perform->aes(&op);
7628c2ecf20Sopenharmony_ci			if (ret) {
7638c2ecf20Sopenharmony_ci				cmd->engine_error = cmd_q->cmd_error;
7648c2ecf20Sopenharmony_ci				goto e_aad;
7658c2ecf20Sopenharmony_ci			}
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci			ccp_process_data(&aad, NULL, &op);
7688c2ecf20Sopenharmony_ci			op.init = 0;
7698c2ecf20Sopenharmony_ci		}
7708c2ecf20Sopenharmony_ci	}
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	op.u.aes.mode = CCP_AES_MODE_GCTR;
7738c2ecf20Sopenharmony_ci	op.u.aes.action = aes->action;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	if (ilen > 0) {
7768c2ecf20Sopenharmony_ci		/* Step 2: Run a GCTR over the plaintext */
7778c2ecf20Sopenharmony_ci		in_place = (sg_virt(p_inp) == sg_virt(p_outp)) ? true : false;
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci		ret = ccp_init_data(&src, cmd_q, p_inp, ilen,
7808c2ecf20Sopenharmony_ci				    AES_BLOCK_SIZE,
7818c2ecf20Sopenharmony_ci				    in_place ? DMA_BIDIRECTIONAL
7828c2ecf20Sopenharmony_ci					     : DMA_TO_DEVICE);
7838c2ecf20Sopenharmony_ci		if (ret)
7848c2ecf20Sopenharmony_ci			goto e_aad;
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci		if (in_place) {
7878c2ecf20Sopenharmony_ci			dst = src;
7888c2ecf20Sopenharmony_ci		} else {
7898c2ecf20Sopenharmony_ci			ret = ccp_init_data(&dst, cmd_q, p_outp, ilen,
7908c2ecf20Sopenharmony_ci					    AES_BLOCK_SIZE, DMA_FROM_DEVICE);
7918c2ecf20Sopenharmony_ci			if (ret)
7928c2ecf20Sopenharmony_ci				goto e_src;
7938c2ecf20Sopenharmony_ci		}
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci		op.soc = 0;
7968c2ecf20Sopenharmony_ci		op.eom = 0;
7978c2ecf20Sopenharmony_ci		op.init = 1;
7988c2ecf20Sopenharmony_ci		while (src.sg_wa.bytes_left) {
7998c2ecf20Sopenharmony_ci			ccp_prepare_data(&src, &dst, &op, AES_BLOCK_SIZE, true);
8008c2ecf20Sopenharmony_ci			if (!src.sg_wa.bytes_left) {
8018c2ecf20Sopenharmony_ci				unsigned int nbytes = ilen % AES_BLOCK_SIZE;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci				if (nbytes) {
8048c2ecf20Sopenharmony_ci					op.eom = 1;
8058c2ecf20Sopenharmony_ci					op.u.aes.size = (nbytes * 8) - 1;
8068c2ecf20Sopenharmony_ci				}
8078c2ecf20Sopenharmony_ci			}
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci			ret = cmd_q->ccp->vdata->perform->aes(&op);
8108c2ecf20Sopenharmony_ci			if (ret) {
8118c2ecf20Sopenharmony_ci				cmd->engine_error = cmd_q->cmd_error;
8128c2ecf20Sopenharmony_ci				goto e_dst;
8138c2ecf20Sopenharmony_ci			}
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci			ccp_process_data(&src, &dst, &op);
8168c2ecf20Sopenharmony_ci			op.init = 0;
8178c2ecf20Sopenharmony_ci		}
8188c2ecf20Sopenharmony_ci	}
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	/* Step 3: Update the IV portion of the context with the original IV */
8218c2ecf20Sopenharmony_ci	ret = ccp_copy_from_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
8228c2ecf20Sopenharmony_ci			       CCP_PASSTHRU_BYTESWAP_256BIT);
8238c2ecf20Sopenharmony_ci	if (ret) {
8248c2ecf20Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
8258c2ecf20Sopenharmony_ci		goto e_dst;
8268c2ecf20Sopenharmony_ci	}
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	ret = ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
8298c2ecf20Sopenharmony_ci	if (ret)
8308c2ecf20Sopenharmony_ci		goto e_dst;
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
8338c2ecf20Sopenharmony_ci			     CCP_PASSTHRU_BYTESWAP_256BIT);
8348c2ecf20Sopenharmony_ci	if (ret) {
8358c2ecf20Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
8368c2ecf20Sopenharmony_ci		goto e_dst;
8378c2ecf20Sopenharmony_ci	}
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci	/* Step 4: Concatenate the lengths of the AAD and source, and
8408c2ecf20Sopenharmony_ci	 * hash that 16 byte buffer.
8418c2ecf20Sopenharmony_ci	 */
8428c2ecf20Sopenharmony_ci	ret = ccp_init_dm_workarea(&final_wa, cmd_q, AES_BLOCK_SIZE,
8438c2ecf20Sopenharmony_ci				   DMA_BIDIRECTIONAL);
8448c2ecf20Sopenharmony_ci	if (ret)
8458c2ecf20Sopenharmony_ci		goto e_dst;
8468c2ecf20Sopenharmony_ci	final = (__be64 *)final_wa.address;
8478c2ecf20Sopenharmony_ci	final[0] = cpu_to_be64(aes->aad_len * 8);
8488c2ecf20Sopenharmony_ci	final[1] = cpu_to_be64(ilen * 8);
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	memset(&op, 0, sizeof(op));
8518c2ecf20Sopenharmony_ci	op.cmd_q = cmd_q;
8528c2ecf20Sopenharmony_ci	op.jobid = jobid;
8538c2ecf20Sopenharmony_ci	op.sb_key = cmd_q->sb_key; /* Pre-allocated */
8548c2ecf20Sopenharmony_ci	op.sb_ctx = cmd_q->sb_ctx; /* Pre-allocated */
8558c2ecf20Sopenharmony_ci	op.init = 1;
8568c2ecf20Sopenharmony_ci	op.u.aes.type = aes->type;
8578c2ecf20Sopenharmony_ci	op.u.aes.mode = CCP_AES_MODE_GHASH;
8588c2ecf20Sopenharmony_ci	op.u.aes.action = CCP_AES_GHASHFINAL;
8598c2ecf20Sopenharmony_ci	op.src.type = CCP_MEMTYPE_SYSTEM;
8608c2ecf20Sopenharmony_ci	op.src.u.dma.address = final_wa.dma.address;
8618c2ecf20Sopenharmony_ci	op.src.u.dma.length = AES_BLOCK_SIZE;
8628c2ecf20Sopenharmony_ci	op.dst.type = CCP_MEMTYPE_SYSTEM;
8638c2ecf20Sopenharmony_ci	op.dst.u.dma.address = final_wa.dma.address;
8648c2ecf20Sopenharmony_ci	op.dst.u.dma.length = AES_BLOCK_SIZE;
8658c2ecf20Sopenharmony_ci	op.eom = 1;
8668c2ecf20Sopenharmony_ci	op.u.aes.size = 0;
8678c2ecf20Sopenharmony_ci	ret = cmd_q->ccp->vdata->perform->aes(&op);
8688c2ecf20Sopenharmony_ci	if (ret)
8698c2ecf20Sopenharmony_ci		goto e_final_wa;
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	if (aes->action == CCP_AES_ACTION_ENCRYPT) {
8728c2ecf20Sopenharmony_ci		/* Put the ciphered tag after the ciphertext. */
8738c2ecf20Sopenharmony_ci		ccp_get_dm_area(&final_wa, 0, p_tag, 0, authsize);
8748c2ecf20Sopenharmony_ci	} else {
8758c2ecf20Sopenharmony_ci		/* Does this ciphered tag match the input? */
8768c2ecf20Sopenharmony_ci		ret = ccp_init_dm_workarea(&tag, cmd_q, authsize,
8778c2ecf20Sopenharmony_ci					   DMA_BIDIRECTIONAL);
8788c2ecf20Sopenharmony_ci		if (ret)
8798c2ecf20Sopenharmony_ci			goto e_final_wa;
8808c2ecf20Sopenharmony_ci		ret = ccp_set_dm_area(&tag, 0, p_tag, 0, authsize);
8818c2ecf20Sopenharmony_ci		if (ret) {
8828c2ecf20Sopenharmony_ci			ccp_dm_free(&tag);
8838c2ecf20Sopenharmony_ci			goto e_final_wa;
8848c2ecf20Sopenharmony_ci		}
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci		ret = crypto_memneq(tag.address, final_wa.address,
8878c2ecf20Sopenharmony_ci				    authsize) ? -EBADMSG : 0;
8888c2ecf20Sopenharmony_ci		ccp_dm_free(&tag);
8898c2ecf20Sopenharmony_ci	}
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_cie_final_wa:
8928c2ecf20Sopenharmony_ci	ccp_dm_free(&final_wa);
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_cie_dst:
8958c2ecf20Sopenharmony_ci	if (ilen > 0 && !in_place)
8968c2ecf20Sopenharmony_ci		ccp_free_data(&dst, cmd_q);
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_cie_src:
8998c2ecf20Sopenharmony_ci	if (ilen > 0)
9008c2ecf20Sopenharmony_ci		ccp_free_data(&src, cmd_q);
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_cie_aad:
9038c2ecf20Sopenharmony_ci	if (aes->aad_len)
9048c2ecf20Sopenharmony_ci		ccp_free_data(&aad, cmd_q);
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_cie_ctx:
9078c2ecf20Sopenharmony_ci	ccp_dm_free(&ctx);
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_cie_key:
9108c2ecf20Sopenharmony_ci	ccp_dm_free(&key);
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	return ret;
9138c2ecf20Sopenharmony_ci}
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_cistatic noinline_for_stack int
9168c2ecf20Sopenharmony_ciccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
9178c2ecf20Sopenharmony_ci{
9188c2ecf20Sopenharmony_ci	struct ccp_aes_engine *aes = &cmd->u.aes;
9198c2ecf20Sopenharmony_ci	struct ccp_dm_workarea key, ctx;
9208c2ecf20Sopenharmony_ci	struct ccp_data src, dst;
9218c2ecf20Sopenharmony_ci	struct ccp_op op;
9228c2ecf20Sopenharmony_ci	unsigned int dm_offset;
9238c2ecf20Sopenharmony_ci	bool in_place = false;
9248c2ecf20Sopenharmony_ci	int ret;
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	if (!((aes->key_len == AES_KEYSIZE_128) ||
9278c2ecf20Sopenharmony_ci	      (aes->key_len == AES_KEYSIZE_192) ||
9288c2ecf20Sopenharmony_ci	      (aes->key_len == AES_KEYSIZE_256)))
9298c2ecf20Sopenharmony_ci		return -EINVAL;
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	if (((aes->mode == CCP_AES_MODE_ECB) ||
9328c2ecf20Sopenharmony_ci	     (aes->mode == CCP_AES_MODE_CBC)) &&
9338c2ecf20Sopenharmony_ci	    (aes->src_len & (AES_BLOCK_SIZE - 1)))
9348c2ecf20Sopenharmony_ci		return -EINVAL;
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	if (!aes->key || !aes->src || !aes->dst)
9378c2ecf20Sopenharmony_ci		return -EINVAL;
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	if (aes->mode != CCP_AES_MODE_ECB) {
9408c2ecf20Sopenharmony_ci		if (aes->iv_len != AES_BLOCK_SIZE)
9418c2ecf20Sopenharmony_ci			return -EINVAL;
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci		if (!aes->iv)
9448c2ecf20Sopenharmony_ci			return -EINVAL;
9458c2ecf20Sopenharmony_ci	}
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	BUILD_BUG_ON(CCP_AES_KEY_SB_COUNT != 1);
9488c2ecf20Sopenharmony_ci	BUILD_BUG_ON(CCP_AES_CTX_SB_COUNT != 1);
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	ret = -EIO;
9518c2ecf20Sopenharmony_ci	memset(&op, 0, sizeof(op));
9528c2ecf20Sopenharmony_ci	op.cmd_q = cmd_q;
9538c2ecf20Sopenharmony_ci	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
9548c2ecf20Sopenharmony_ci	op.sb_key = cmd_q->sb_key;
9558c2ecf20Sopenharmony_ci	op.sb_ctx = cmd_q->sb_ctx;
9568c2ecf20Sopenharmony_ci	op.init = (aes->mode == CCP_AES_MODE_ECB) ? 0 : 1;
9578c2ecf20Sopenharmony_ci	op.u.aes.type = aes->type;
9588c2ecf20Sopenharmony_ci	op.u.aes.mode = aes->mode;
9598c2ecf20Sopenharmony_ci	op.u.aes.action = aes->action;
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	/* All supported key sizes fit in a single (32-byte) SB entry
9628c2ecf20Sopenharmony_ci	 * and must be in little endian format. Use the 256-bit byte
9638c2ecf20Sopenharmony_ci	 * swap passthru option to convert from big endian to little
9648c2ecf20Sopenharmony_ci	 * endian.
9658c2ecf20Sopenharmony_ci	 */
9668c2ecf20Sopenharmony_ci	ret = ccp_init_dm_workarea(&key, cmd_q,
9678c2ecf20Sopenharmony_ci				   CCP_AES_KEY_SB_COUNT * CCP_SB_BYTES,
9688c2ecf20Sopenharmony_ci				   DMA_TO_DEVICE);
9698c2ecf20Sopenharmony_ci	if (ret)
9708c2ecf20Sopenharmony_ci		return ret;
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	dm_offset = CCP_SB_BYTES - aes->key_len;
9738c2ecf20Sopenharmony_ci	ret = ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len);
9748c2ecf20Sopenharmony_ci	if (ret)
9758c2ecf20Sopenharmony_ci		goto e_key;
9768c2ecf20Sopenharmony_ci	ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
9778c2ecf20Sopenharmony_ci			     CCP_PASSTHRU_BYTESWAP_256BIT);
9788c2ecf20Sopenharmony_ci	if (ret) {
9798c2ecf20Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
9808c2ecf20Sopenharmony_ci		goto e_key;
9818c2ecf20Sopenharmony_ci	}
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	/* The AES context fits in a single (32-byte) SB entry and
9848c2ecf20Sopenharmony_ci	 * must be in little endian format. Use the 256-bit byte swap
9858c2ecf20Sopenharmony_ci	 * passthru option to convert from big endian to little endian.
9868c2ecf20Sopenharmony_ci	 */
9878c2ecf20Sopenharmony_ci	ret = ccp_init_dm_workarea(&ctx, cmd_q,
9888c2ecf20Sopenharmony_ci				   CCP_AES_CTX_SB_COUNT * CCP_SB_BYTES,
9898c2ecf20Sopenharmony_ci				   DMA_BIDIRECTIONAL);
9908c2ecf20Sopenharmony_ci	if (ret)
9918c2ecf20Sopenharmony_ci		goto e_key;
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	if (aes->mode != CCP_AES_MODE_ECB) {
9948c2ecf20Sopenharmony_ci		/* Load the AES context - convert to LE */
9958c2ecf20Sopenharmony_ci		dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
9968c2ecf20Sopenharmony_ci		ret = ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
9978c2ecf20Sopenharmony_ci		if (ret)
9988c2ecf20Sopenharmony_ci			goto e_ctx;
9998c2ecf20Sopenharmony_ci		ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
10008c2ecf20Sopenharmony_ci				     CCP_PASSTHRU_BYTESWAP_256BIT);
10018c2ecf20Sopenharmony_ci		if (ret) {
10028c2ecf20Sopenharmony_ci			cmd->engine_error = cmd_q->cmd_error;
10038c2ecf20Sopenharmony_ci			goto e_ctx;
10048c2ecf20Sopenharmony_ci		}
10058c2ecf20Sopenharmony_ci	}
10068c2ecf20Sopenharmony_ci	switch (aes->mode) {
10078c2ecf20Sopenharmony_ci	case CCP_AES_MODE_CFB: /* CFB128 only */
10088c2ecf20Sopenharmony_ci	case CCP_AES_MODE_CTR:
10098c2ecf20Sopenharmony_ci		op.u.aes.size = AES_BLOCK_SIZE * BITS_PER_BYTE - 1;
10108c2ecf20Sopenharmony_ci		break;
10118c2ecf20Sopenharmony_ci	default:
10128c2ecf20Sopenharmony_ci		op.u.aes.size = 0;
10138c2ecf20Sopenharmony_ci	}
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci	/* Prepare the input and output data workareas. For in-place
10168c2ecf20Sopenharmony_ci	 * operations we need to set the dma direction to BIDIRECTIONAL
10178c2ecf20Sopenharmony_ci	 * and copy the src workarea to the dst workarea.
10188c2ecf20Sopenharmony_ci	 */
10198c2ecf20Sopenharmony_ci	if (sg_virt(aes->src) == sg_virt(aes->dst))
10208c2ecf20Sopenharmony_ci		in_place = true;
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	ret = ccp_init_data(&src, cmd_q, aes->src, aes->src_len,
10238c2ecf20Sopenharmony_ci			    AES_BLOCK_SIZE,
10248c2ecf20Sopenharmony_ci			    in_place ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE);
10258c2ecf20Sopenharmony_ci	if (ret)
10268c2ecf20Sopenharmony_ci		goto e_ctx;
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	if (in_place) {
10298c2ecf20Sopenharmony_ci		dst = src;
10308c2ecf20Sopenharmony_ci	} else {
10318c2ecf20Sopenharmony_ci		ret = ccp_init_data(&dst, cmd_q, aes->dst, aes->src_len,
10328c2ecf20Sopenharmony_ci				    AES_BLOCK_SIZE, DMA_FROM_DEVICE);
10338c2ecf20Sopenharmony_ci		if (ret)
10348c2ecf20Sopenharmony_ci			goto e_src;
10358c2ecf20Sopenharmony_ci	}
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci	/* Send data to the CCP AES engine */
10388c2ecf20Sopenharmony_ci	while (src.sg_wa.bytes_left) {
10398c2ecf20Sopenharmony_ci		ccp_prepare_data(&src, &dst, &op, AES_BLOCK_SIZE, true);
10408c2ecf20Sopenharmony_ci		if (!src.sg_wa.bytes_left) {
10418c2ecf20Sopenharmony_ci			op.eom = 1;
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci			/* Since we don't retrieve the AES context in ECB
10448c2ecf20Sopenharmony_ci			 * mode we have to wait for the operation to complete
10458c2ecf20Sopenharmony_ci			 * on the last piece of data
10468c2ecf20Sopenharmony_ci			 */
10478c2ecf20Sopenharmony_ci			if (aes->mode == CCP_AES_MODE_ECB)
10488c2ecf20Sopenharmony_ci				op.soc = 1;
10498c2ecf20Sopenharmony_ci		}
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci		ret = cmd_q->ccp->vdata->perform->aes(&op);
10528c2ecf20Sopenharmony_ci		if (ret) {
10538c2ecf20Sopenharmony_ci			cmd->engine_error = cmd_q->cmd_error;
10548c2ecf20Sopenharmony_ci			goto e_dst;
10558c2ecf20Sopenharmony_ci		}
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci		ccp_process_data(&src, &dst, &op);
10588c2ecf20Sopenharmony_ci	}
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci	if (aes->mode != CCP_AES_MODE_ECB) {
10618c2ecf20Sopenharmony_ci		/* Retrieve the AES context - convert from LE to BE using
10628c2ecf20Sopenharmony_ci		 * 32-byte (256-bit) byteswapping
10638c2ecf20Sopenharmony_ci		 */
10648c2ecf20Sopenharmony_ci		ret = ccp_copy_from_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
10658c2ecf20Sopenharmony_ci				       CCP_PASSTHRU_BYTESWAP_256BIT);
10668c2ecf20Sopenharmony_ci		if (ret) {
10678c2ecf20Sopenharmony_ci			cmd->engine_error = cmd_q->cmd_error;
10688c2ecf20Sopenharmony_ci			goto e_dst;
10698c2ecf20Sopenharmony_ci		}
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci		/* ...but we only need AES_BLOCK_SIZE bytes */
10728c2ecf20Sopenharmony_ci		dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
10738c2ecf20Sopenharmony_ci		ccp_get_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
10748c2ecf20Sopenharmony_ci	}
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_cie_dst:
10778c2ecf20Sopenharmony_ci	if (!in_place)
10788c2ecf20Sopenharmony_ci		ccp_free_data(&dst, cmd_q);
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_cie_src:
10818c2ecf20Sopenharmony_ci	ccp_free_data(&src, cmd_q);
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_cie_ctx:
10848c2ecf20Sopenharmony_ci	ccp_dm_free(&ctx);
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_cie_key:
10878c2ecf20Sopenharmony_ci	ccp_dm_free(&key);
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	return ret;
10908c2ecf20Sopenharmony_ci}
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_cistatic noinline_for_stack int
10938c2ecf20Sopenharmony_ciccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
10948c2ecf20Sopenharmony_ci{
10958c2ecf20Sopenharmony_ci	struct ccp_xts_aes_engine *xts = &cmd->u.xts;
10968c2ecf20Sopenharmony_ci	struct ccp_dm_workarea key, ctx;
10978c2ecf20Sopenharmony_ci	struct ccp_data src, dst;
10988c2ecf20Sopenharmony_ci	struct ccp_op op;
10998c2ecf20Sopenharmony_ci	unsigned int unit_size, dm_offset;
11008c2ecf20Sopenharmony_ci	bool in_place = false;
11018c2ecf20Sopenharmony_ci	unsigned int sb_count;
11028c2ecf20Sopenharmony_ci	enum ccp_aes_type aestype;
11038c2ecf20Sopenharmony_ci	int ret;
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	switch (xts->unit_size) {
11068c2ecf20Sopenharmony_ci	case CCP_XTS_AES_UNIT_SIZE_16:
11078c2ecf20Sopenharmony_ci		unit_size = 16;
11088c2ecf20Sopenharmony_ci		break;
11098c2ecf20Sopenharmony_ci	case CCP_XTS_AES_UNIT_SIZE_512:
11108c2ecf20Sopenharmony_ci		unit_size = 512;
11118c2ecf20Sopenharmony_ci		break;
11128c2ecf20Sopenharmony_ci	case CCP_XTS_AES_UNIT_SIZE_1024:
11138c2ecf20Sopenharmony_ci		unit_size = 1024;
11148c2ecf20Sopenharmony_ci		break;
11158c2ecf20Sopenharmony_ci	case CCP_XTS_AES_UNIT_SIZE_2048:
11168c2ecf20Sopenharmony_ci		unit_size = 2048;
11178c2ecf20Sopenharmony_ci		break;
11188c2ecf20Sopenharmony_ci	case CCP_XTS_AES_UNIT_SIZE_4096:
11198c2ecf20Sopenharmony_ci		unit_size = 4096;
11208c2ecf20Sopenharmony_ci		break;
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci	default:
11238c2ecf20Sopenharmony_ci		return -EINVAL;
11248c2ecf20Sopenharmony_ci	}
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci	if (xts->key_len == AES_KEYSIZE_128)
11278c2ecf20Sopenharmony_ci		aestype = CCP_AES_TYPE_128;
11288c2ecf20Sopenharmony_ci	else if (xts->key_len == AES_KEYSIZE_256)
11298c2ecf20Sopenharmony_ci		aestype = CCP_AES_TYPE_256;
11308c2ecf20Sopenharmony_ci	else
11318c2ecf20Sopenharmony_ci		return -EINVAL;
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci	if (!xts->final && (xts->src_len & (AES_BLOCK_SIZE - 1)))
11348c2ecf20Sopenharmony_ci		return -EINVAL;
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci	if (xts->iv_len != AES_BLOCK_SIZE)
11378c2ecf20Sopenharmony_ci		return -EINVAL;
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	if (!xts->key || !xts->iv || !xts->src || !xts->dst)
11408c2ecf20Sopenharmony_ci		return -EINVAL;
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci	BUILD_BUG_ON(CCP_XTS_AES_KEY_SB_COUNT != 1);
11438c2ecf20Sopenharmony_ci	BUILD_BUG_ON(CCP_XTS_AES_CTX_SB_COUNT != 1);
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci	ret = -EIO;
11468c2ecf20Sopenharmony_ci	memset(&op, 0, sizeof(op));
11478c2ecf20Sopenharmony_ci	op.cmd_q = cmd_q;
11488c2ecf20Sopenharmony_ci	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
11498c2ecf20Sopenharmony_ci	op.sb_key = cmd_q->sb_key;
11508c2ecf20Sopenharmony_ci	op.sb_ctx = cmd_q->sb_ctx;
11518c2ecf20Sopenharmony_ci	op.init = 1;
11528c2ecf20Sopenharmony_ci	op.u.xts.type = aestype;
11538c2ecf20Sopenharmony_ci	op.u.xts.action = xts->action;
11548c2ecf20Sopenharmony_ci	op.u.xts.unit_size = xts->unit_size;
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci	/* A version 3 device only supports 128-bit keys, which fits into a
11578c2ecf20Sopenharmony_ci	 * single SB entry. A version 5 device uses a 512-bit vector, so two
11588c2ecf20Sopenharmony_ci	 * SB entries.
11598c2ecf20Sopenharmony_ci	 */
11608c2ecf20Sopenharmony_ci	if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0))
11618c2ecf20Sopenharmony_ci		sb_count = CCP_XTS_AES_KEY_SB_COUNT;
11628c2ecf20Sopenharmony_ci	else
11638c2ecf20Sopenharmony_ci		sb_count = CCP5_XTS_AES_KEY_SB_COUNT;
11648c2ecf20Sopenharmony_ci	ret = ccp_init_dm_workarea(&key, cmd_q,
11658c2ecf20Sopenharmony_ci				   sb_count * CCP_SB_BYTES,
11668c2ecf20Sopenharmony_ci				   DMA_TO_DEVICE);
11678c2ecf20Sopenharmony_ci	if (ret)
11688c2ecf20Sopenharmony_ci		return ret;
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci	if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0)) {
11718c2ecf20Sopenharmony_ci		/* All supported key sizes must be in little endian format.
11728c2ecf20Sopenharmony_ci		 * Use the 256-bit byte swap passthru option to convert from
11738c2ecf20Sopenharmony_ci		 * big endian to little endian.
11748c2ecf20Sopenharmony_ci		 */
11758c2ecf20Sopenharmony_ci		dm_offset = CCP_SB_BYTES - AES_KEYSIZE_128;
11768c2ecf20Sopenharmony_ci		ret = ccp_set_dm_area(&key, dm_offset, xts->key, 0, xts->key_len);
11778c2ecf20Sopenharmony_ci		if (ret)
11788c2ecf20Sopenharmony_ci			goto e_key;
11798c2ecf20Sopenharmony_ci		ret = ccp_set_dm_area(&key, 0, xts->key, xts->key_len, xts->key_len);
11808c2ecf20Sopenharmony_ci		if (ret)
11818c2ecf20Sopenharmony_ci			goto e_key;
11828c2ecf20Sopenharmony_ci	} else {
11838c2ecf20Sopenharmony_ci		/* Version 5 CCPs use a 512-bit space for the key: each portion
11848c2ecf20Sopenharmony_ci		 * occupies 256 bits, or one entire slot, and is zero-padded.
11858c2ecf20Sopenharmony_ci		 */
11868c2ecf20Sopenharmony_ci		unsigned int pad;
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci		dm_offset = CCP_SB_BYTES;
11898c2ecf20Sopenharmony_ci		pad = dm_offset - xts->key_len;
11908c2ecf20Sopenharmony_ci		ret = ccp_set_dm_area(&key, pad, xts->key, 0, xts->key_len);
11918c2ecf20Sopenharmony_ci		if (ret)
11928c2ecf20Sopenharmony_ci			goto e_key;
11938c2ecf20Sopenharmony_ci		ret = ccp_set_dm_area(&key, dm_offset + pad, xts->key,
11948c2ecf20Sopenharmony_ci				      xts->key_len, xts->key_len);
11958c2ecf20Sopenharmony_ci		if (ret)
11968c2ecf20Sopenharmony_ci			goto e_key;
11978c2ecf20Sopenharmony_ci	}
11988c2ecf20Sopenharmony_ci	ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
11998c2ecf20Sopenharmony_ci			     CCP_PASSTHRU_BYTESWAP_256BIT);
12008c2ecf20Sopenharmony_ci	if (ret) {
12018c2ecf20Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
12028c2ecf20Sopenharmony_ci		goto e_key;
12038c2ecf20Sopenharmony_ci	}
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	/* The AES context fits in a single (32-byte) SB entry and
12068c2ecf20Sopenharmony_ci	 * for XTS is already in little endian format so no byte swapping
12078c2ecf20Sopenharmony_ci	 * is needed.
12088c2ecf20Sopenharmony_ci	 */
12098c2ecf20Sopenharmony_ci	ret = ccp_init_dm_workarea(&ctx, cmd_q,
12108c2ecf20Sopenharmony_ci				   CCP_XTS_AES_CTX_SB_COUNT * CCP_SB_BYTES,
12118c2ecf20Sopenharmony_ci				   DMA_BIDIRECTIONAL);
12128c2ecf20Sopenharmony_ci	if (ret)
12138c2ecf20Sopenharmony_ci		goto e_key;
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci	ret = ccp_set_dm_area(&ctx, 0, xts->iv, 0, xts->iv_len);
12168c2ecf20Sopenharmony_ci	if (ret)
12178c2ecf20Sopenharmony_ci		goto e_ctx;
12188c2ecf20Sopenharmony_ci	ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
12198c2ecf20Sopenharmony_ci			     CCP_PASSTHRU_BYTESWAP_NOOP);
12208c2ecf20Sopenharmony_ci	if (ret) {
12218c2ecf20Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
12228c2ecf20Sopenharmony_ci		goto e_ctx;
12238c2ecf20Sopenharmony_ci	}
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci	/* Prepare the input and output data workareas. For in-place
12268c2ecf20Sopenharmony_ci	 * operations we need to set the dma direction to BIDIRECTIONAL
12278c2ecf20Sopenharmony_ci	 * and copy the src workarea to the dst workarea.
12288c2ecf20Sopenharmony_ci	 */
12298c2ecf20Sopenharmony_ci	if (sg_virt(xts->src) == sg_virt(xts->dst))
12308c2ecf20Sopenharmony_ci		in_place = true;
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_ci	ret = ccp_init_data(&src, cmd_q, xts->src, xts->src_len,
12338c2ecf20Sopenharmony_ci			    unit_size,
12348c2ecf20Sopenharmony_ci			    in_place ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE);
12358c2ecf20Sopenharmony_ci	if (ret)
12368c2ecf20Sopenharmony_ci		goto e_ctx;
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci	if (in_place) {
12398c2ecf20Sopenharmony_ci		dst = src;
12408c2ecf20Sopenharmony_ci	} else {
12418c2ecf20Sopenharmony_ci		ret = ccp_init_data(&dst, cmd_q, xts->dst, xts->src_len,
12428c2ecf20Sopenharmony_ci				    unit_size, DMA_FROM_DEVICE);
12438c2ecf20Sopenharmony_ci		if (ret)
12448c2ecf20Sopenharmony_ci			goto e_src;
12458c2ecf20Sopenharmony_ci	}
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci	/* Send data to the CCP AES engine */
12488c2ecf20Sopenharmony_ci	while (src.sg_wa.bytes_left) {
12498c2ecf20Sopenharmony_ci		ccp_prepare_data(&src, &dst, &op, unit_size, true);
12508c2ecf20Sopenharmony_ci		if (!src.sg_wa.bytes_left)
12518c2ecf20Sopenharmony_ci			op.eom = 1;
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci		ret = cmd_q->ccp->vdata->perform->xts_aes(&op);
12548c2ecf20Sopenharmony_ci		if (ret) {
12558c2ecf20Sopenharmony_ci			cmd->engine_error = cmd_q->cmd_error;
12568c2ecf20Sopenharmony_ci			goto e_dst;
12578c2ecf20Sopenharmony_ci		}
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci		ccp_process_data(&src, &dst, &op);
12608c2ecf20Sopenharmony_ci	}
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci	/* Retrieve the AES context - convert from LE to BE using
12638c2ecf20Sopenharmony_ci	 * 32-byte (256-bit) byteswapping
12648c2ecf20Sopenharmony_ci	 */
12658c2ecf20Sopenharmony_ci	ret = ccp_copy_from_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
12668c2ecf20Sopenharmony_ci			       CCP_PASSTHRU_BYTESWAP_256BIT);
12678c2ecf20Sopenharmony_ci	if (ret) {
12688c2ecf20Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
12698c2ecf20Sopenharmony_ci		goto e_dst;
12708c2ecf20Sopenharmony_ci	}
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci	/* ...but we only need AES_BLOCK_SIZE bytes */
12738c2ecf20Sopenharmony_ci	dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
12748c2ecf20Sopenharmony_ci	ccp_get_dm_area(&ctx, dm_offset, xts->iv, 0, xts->iv_len);
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_cie_dst:
12778c2ecf20Sopenharmony_ci	if (!in_place)
12788c2ecf20Sopenharmony_ci		ccp_free_data(&dst, cmd_q);
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_cie_src:
12818c2ecf20Sopenharmony_ci	ccp_free_data(&src, cmd_q);
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_cie_ctx:
12848c2ecf20Sopenharmony_ci	ccp_dm_free(&ctx);
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_cie_key:
12878c2ecf20Sopenharmony_ci	ccp_dm_free(&key);
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci	return ret;
12908c2ecf20Sopenharmony_ci}
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_cistatic noinline_for_stack int
12938c2ecf20Sopenharmony_ciccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
12948c2ecf20Sopenharmony_ci{
12958c2ecf20Sopenharmony_ci	struct ccp_des3_engine *des3 = &cmd->u.des3;
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci	struct ccp_dm_workarea key, ctx;
12988c2ecf20Sopenharmony_ci	struct ccp_data src, dst;
12998c2ecf20Sopenharmony_ci	struct ccp_op op;
13008c2ecf20Sopenharmony_ci	unsigned int dm_offset;
13018c2ecf20Sopenharmony_ci	unsigned int len_singlekey;
13028c2ecf20Sopenharmony_ci	bool in_place = false;
13038c2ecf20Sopenharmony_ci	int ret;
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_ci	/* Error checks */
13068c2ecf20Sopenharmony_ci	if (cmd_q->ccp->vdata->version < CCP_VERSION(5, 0))
13078c2ecf20Sopenharmony_ci		return -EINVAL;
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci	if (!cmd_q->ccp->vdata->perform->des3)
13108c2ecf20Sopenharmony_ci		return -EINVAL;
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	if (des3->key_len != DES3_EDE_KEY_SIZE)
13138c2ecf20Sopenharmony_ci		return -EINVAL;
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci	if (((des3->mode == CCP_DES3_MODE_ECB) ||
13168c2ecf20Sopenharmony_ci		(des3->mode == CCP_DES3_MODE_CBC)) &&
13178c2ecf20Sopenharmony_ci		(des3->src_len & (DES3_EDE_BLOCK_SIZE - 1)))
13188c2ecf20Sopenharmony_ci		return -EINVAL;
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci	if (!des3->key || !des3->src || !des3->dst)
13218c2ecf20Sopenharmony_ci		return -EINVAL;
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci	if (des3->mode != CCP_DES3_MODE_ECB) {
13248c2ecf20Sopenharmony_ci		if (des3->iv_len != DES3_EDE_BLOCK_SIZE)
13258c2ecf20Sopenharmony_ci			return -EINVAL;
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci		if (!des3->iv)
13288c2ecf20Sopenharmony_ci			return -EINVAL;
13298c2ecf20Sopenharmony_ci	}
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_ci	/* Zero out all the fields of the command desc */
13328c2ecf20Sopenharmony_ci	memset(&op, 0, sizeof(op));
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci	/* Set up the Function field */
13358c2ecf20Sopenharmony_ci	op.cmd_q = cmd_q;
13368c2ecf20Sopenharmony_ci	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
13378c2ecf20Sopenharmony_ci	op.sb_key = cmd_q->sb_key;
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci	op.init = (des3->mode == CCP_DES3_MODE_ECB) ? 0 : 1;
13408c2ecf20Sopenharmony_ci	op.u.des3.type = des3->type;
13418c2ecf20Sopenharmony_ci	op.u.des3.mode = des3->mode;
13428c2ecf20Sopenharmony_ci	op.u.des3.action = des3->action;
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci	/*
13458c2ecf20Sopenharmony_ci	 * All supported key sizes fit in a single (32-byte) KSB entry and
13468c2ecf20Sopenharmony_ci	 * (like AES) must be in little endian format. Use the 256-bit byte
13478c2ecf20Sopenharmony_ci	 * swap passthru option to convert from big endian to little endian.
13488c2ecf20Sopenharmony_ci	 */
13498c2ecf20Sopenharmony_ci	ret = ccp_init_dm_workarea(&key, cmd_q,
13508c2ecf20Sopenharmony_ci				   CCP_DES3_KEY_SB_COUNT * CCP_SB_BYTES,
13518c2ecf20Sopenharmony_ci				   DMA_TO_DEVICE);
13528c2ecf20Sopenharmony_ci	if (ret)
13538c2ecf20Sopenharmony_ci		return ret;
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci	/*
13568c2ecf20Sopenharmony_ci	 * The contents of the key triplet are in the reverse order of what
13578c2ecf20Sopenharmony_ci	 * is required by the engine. Copy the 3 pieces individually to put
13588c2ecf20Sopenharmony_ci	 * them where they belong.
13598c2ecf20Sopenharmony_ci	 */
13608c2ecf20Sopenharmony_ci	dm_offset = CCP_SB_BYTES - des3->key_len; /* Basic offset */
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci	len_singlekey = des3->key_len / 3;
13638c2ecf20Sopenharmony_ci	ret = ccp_set_dm_area(&key, dm_offset + 2 * len_singlekey,
13648c2ecf20Sopenharmony_ci			      des3->key, 0, len_singlekey);
13658c2ecf20Sopenharmony_ci	if (ret)
13668c2ecf20Sopenharmony_ci		goto e_key;
13678c2ecf20Sopenharmony_ci	ret = ccp_set_dm_area(&key, dm_offset + len_singlekey,
13688c2ecf20Sopenharmony_ci			      des3->key, len_singlekey, len_singlekey);
13698c2ecf20Sopenharmony_ci	if (ret)
13708c2ecf20Sopenharmony_ci		goto e_key;
13718c2ecf20Sopenharmony_ci	ret = ccp_set_dm_area(&key, dm_offset,
13728c2ecf20Sopenharmony_ci			      des3->key, 2 * len_singlekey, len_singlekey);
13738c2ecf20Sopenharmony_ci	if (ret)
13748c2ecf20Sopenharmony_ci		goto e_key;
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_ci	/* Copy the key to the SB */
13778c2ecf20Sopenharmony_ci	ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
13788c2ecf20Sopenharmony_ci			     CCP_PASSTHRU_BYTESWAP_256BIT);
13798c2ecf20Sopenharmony_ci	if (ret) {
13808c2ecf20Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
13818c2ecf20Sopenharmony_ci		goto e_key;
13828c2ecf20Sopenharmony_ci	}
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_ci	/*
13858c2ecf20Sopenharmony_ci	 * The DES3 context fits in a single (32-byte) KSB entry and
13868c2ecf20Sopenharmony_ci	 * must be in little endian format. Use the 256-bit byte swap
13878c2ecf20Sopenharmony_ci	 * passthru option to convert from big endian to little endian.
13888c2ecf20Sopenharmony_ci	 */
13898c2ecf20Sopenharmony_ci	if (des3->mode != CCP_DES3_MODE_ECB) {
13908c2ecf20Sopenharmony_ci		op.sb_ctx = cmd_q->sb_ctx;
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci		ret = ccp_init_dm_workarea(&ctx, cmd_q,
13938c2ecf20Sopenharmony_ci					   CCP_DES3_CTX_SB_COUNT * CCP_SB_BYTES,
13948c2ecf20Sopenharmony_ci					   DMA_BIDIRECTIONAL);
13958c2ecf20Sopenharmony_ci		if (ret)
13968c2ecf20Sopenharmony_ci			goto e_key;
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci		/* Load the context into the LSB */
13998c2ecf20Sopenharmony_ci		dm_offset = CCP_SB_BYTES - des3->iv_len;
14008c2ecf20Sopenharmony_ci		ret = ccp_set_dm_area(&ctx, dm_offset, des3->iv, 0,
14018c2ecf20Sopenharmony_ci				      des3->iv_len);
14028c2ecf20Sopenharmony_ci		if (ret)
14038c2ecf20Sopenharmony_ci			goto e_ctx;
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci		ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
14068c2ecf20Sopenharmony_ci				     CCP_PASSTHRU_BYTESWAP_256BIT);
14078c2ecf20Sopenharmony_ci		if (ret) {
14088c2ecf20Sopenharmony_ci			cmd->engine_error = cmd_q->cmd_error;
14098c2ecf20Sopenharmony_ci			goto e_ctx;
14108c2ecf20Sopenharmony_ci		}
14118c2ecf20Sopenharmony_ci	}
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci	/*
14148c2ecf20Sopenharmony_ci	 * Prepare the input and output data workareas. For in-place
14158c2ecf20Sopenharmony_ci	 * operations we need to set the dma direction to BIDIRECTIONAL
14168c2ecf20Sopenharmony_ci	 * and copy the src workarea to the dst workarea.
14178c2ecf20Sopenharmony_ci	 */
14188c2ecf20Sopenharmony_ci	if (sg_virt(des3->src) == sg_virt(des3->dst))
14198c2ecf20Sopenharmony_ci		in_place = true;
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci	ret = ccp_init_data(&src, cmd_q, des3->src, des3->src_len,
14228c2ecf20Sopenharmony_ci			DES3_EDE_BLOCK_SIZE,
14238c2ecf20Sopenharmony_ci			in_place ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE);
14248c2ecf20Sopenharmony_ci	if (ret)
14258c2ecf20Sopenharmony_ci		goto e_ctx;
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_ci	if (in_place)
14288c2ecf20Sopenharmony_ci		dst = src;
14298c2ecf20Sopenharmony_ci	else {
14308c2ecf20Sopenharmony_ci		ret = ccp_init_data(&dst, cmd_q, des3->dst, des3->src_len,
14318c2ecf20Sopenharmony_ci				DES3_EDE_BLOCK_SIZE, DMA_FROM_DEVICE);
14328c2ecf20Sopenharmony_ci		if (ret)
14338c2ecf20Sopenharmony_ci			goto e_src;
14348c2ecf20Sopenharmony_ci	}
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	/* Send data to the CCP DES3 engine */
14378c2ecf20Sopenharmony_ci	while (src.sg_wa.bytes_left) {
14388c2ecf20Sopenharmony_ci		ccp_prepare_data(&src, &dst, &op, DES3_EDE_BLOCK_SIZE, true);
14398c2ecf20Sopenharmony_ci		if (!src.sg_wa.bytes_left) {
14408c2ecf20Sopenharmony_ci			op.eom = 1;
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci			/* Since we don't retrieve the context in ECB mode
14438c2ecf20Sopenharmony_ci			 * we have to wait for the operation to complete
14448c2ecf20Sopenharmony_ci			 * on the last piece of data
14458c2ecf20Sopenharmony_ci			 */
14468c2ecf20Sopenharmony_ci			op.soc = 0;
14478c2ecf20Sopenharmony_ci		}
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci		ret = cmd_q->ccp->vdata->perform->des3(&op);
14508c2ecf20Sopenharmony_ci		if (ret) {
14518c2ecf20Sopenharmony_ci			cmd->engine_error = cmd_q->cmd_error;
14528c2ecf20Sopenharmony_ci			goto e_dst;
14538c2ecf20Sopenharmony_ci		}
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci		ccp_process_data(&src, &dst, &op);
14568c2ecf20Sopenharmony_ci	}
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ci	if (des3->mode != CCP_DES3_MODE_ECB) {
14598c2ecf20Sopenharmony_ci		/* Retrieve the context and make BE */
14608c2ecf20Sopenharmony_ci		ret = ccp_copy_from_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
14618c2ecf20Sopenharmony_ci				       CCP_PASSTHRU_BYTESWAP_256BIT);
14628c2ecf20Sopenharmony_ci		if (ret) {
14638c2ecf20Sopenharmony_ci			cmd->engine_error = cmd_q->cmd_error;
14648c2ecf20Sopenharmony_ci			goto e_dst;
14658c2ecf20Sopenharmony_ci		}
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci		/* ...but we only need the last DES3_EDE_BLOCK_SIZE bytes */
14688c2ecf20Sopenharmony_ci		ccp_get_dm_area(&ctx, dm_offset, des3->iv, 0,
14698c2ecf20Sopenharmony_ci				DES3_EDE_BLOCK_SIZE);
14708c2ecf20Sopenharmony_ci	}
14718c2ecf20Sopenharmony_cie_dst:
14728c2ecf20Sopenharmony_ci	if (!in_place)
14738c2ecf20Sopenharmony_ci		ccp_free_data(&dst, cmd_q);
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_cie_src:
14768c2ecf20Sopenharmony_ci	ccp_free_data(&src, cmd_q);
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_cie_ctx:
14798c2ecf20Sopenharmony_ci	if (des3->mode != CCP_DES3_MODE_ECB)
14808c2ecf20Sopenharmony_ci		ccp_dm_free(&ctx);
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_cie_key:
14838c2ecf20Sopenharmony_ci	ccp_dm_free(&key);
14848c2ecf20Sopenharmony_ci
14858c2ecf20Sopenharmony_ci	return ret;
14868c2ecf20Sopenharmony_ci}
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_cistatic noinline_for_stack int
14898c2ecf20Sopenharmony_ciccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
14908c2ecf20Sopenharmony_ci{
14918c2ecf20Sopenharmony_ci	struct ccp_sha_engine *sha = &cmd->u.sha;
14928c2ecf20Sopenharmony_ci	struct ccp_dm_workarea ctx;
14938c2ecf20Sopenharmony_ci	struct ccp_data src;
14948c2ecf20Sopenharmony_ci	struct ccp_op op;
14958c2ecf20Sopenharmony_ci	unsigned int ioffset, ooffset;
14968c2ecf20Sopenharmony_ci	unsigned int digest_size;
14978c2ecf20Sopenharmony_ci	int sb_count;
14988c2ecf20Sopenharmony_ci	const void *init;
14998c2ecf20Sopenharmony_ci	u64 block_size;
15008c2ecf20Sopenharmony_ci	int ctx_size;
15018c2ecf20Sopenharmony_ci	int ret;
15028c2ecf20Sopenharmony_ci
15038c2ecf20Sopenharmony_ci	switch (sha->type) {
15048c2ecf20Sopenharmony_ci	case CCP_SHA_TYPE_1:
15058c2ecf20Sopenharmony_ci		if (sha->ctx_len < SHA1_DIGEST_SIZE)
15068c2ecf20Sopenharmony_ci			return -EINVAL;
15078c2ecf20Sopenharmony_ci		block_size = SHA1_BLOCK_SIZE;
15088c2ecf20Sopenharmony_ci		break;
15098c2ecf20Sopenharmony_ci	case CCP_SHA_TYPE_224:
15108c2ecf20Sopenharmony_ci		if (sha->ctx_len < SHA224_DIGEST_SIZE)
15118c2ecf20Sopenharmony_ci			return -EINVAL;
15128c2ecf20Sopenharmony_ci		block_size = SHA224_BLOCK_SIZE;
15138c2ecf20Sopenharmony_ci		break;
15148c2ecf20Sopenharmony_ci	case CCP_SHA_TYPE_256:
15158c2ecf20Sopenharmony_ci		if (sha->ctx_len < SHA256_DIGEST_SIZE)
15168c2ecf20Sopenharmony_ci			return -EINVAL;
15178c2ecf20Sopenharmony_ci		block_size = SHA256_BLOCK_SIZE;
15188c2ecf20Sopenharmony_ci		break;
15198c2ecf20Sopenharmony_ci	case CCP_SHA_TYPE_384:
15208c2ecf20Sopenharmony_ci		if (cmd_q->ccp->vdata->version < CCP_VERSION(4, 0)
15218c2ecf20Sopenharmony_ci		    || sha->ctx_len < SHA384_DIGEST_SIZE)
15228c2ecf20Sopenharmony_ci			return -EINVAL;
15238c2ecf20Sopenharmony_ci		block_size = SHA384_BLOCK_SIZE;
15248c2ecf20Sopenharmony_ci		break;
15258c2ecf20Sopenharmony_ci	case CCP_SHA_TYPE_512:
15268c2ecf20Sopenharmony_ci		if (cmd_q->ccp->vdata->version < CCP_VERSION(4, 0)
15278c2ecf20Sopenharmony_ci		    || sha->ctx_len < SHA512_DIGEST_SIZE)
15288c2ecf20Sopenharmony_ci			return -EINVAL;
15298c2ecf20Sopenharmony_ci		block_size = SHA512_BLOCK_SIZE;
15308c2ecf20Sopenharmony_ci		break;
15318c2ecf20Sopenharmony_ci	default:
15328c2ecf20Sopenharmony_ci		return -EINVAL;
15338c2ecf20Sopenharmony_ci	}
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci	if (!sha->ctx)
15368c2ecf20Sopenharmony_ci		return -EINVAL;
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci	if (!sha->final && (sha->src_len & (block_size - 1)))
15398c2ecf20Sopenharmony_ci		return -EINVAL;
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci	/* The version 3 device can't handle zero-length input */
15428c2ecf20Sopenharmony_ci	if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0)) {
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_ci		if (!sha->src_len) {
15458c2ecf20Sopenharmony_ci			unsigned int digest_len;
15468c2ecf20Sopenharmony_ci			const u8 *sha_zero;
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci			/* Not final, just return */
15498c2ecf20Sopenharmony_ci			if (!sha->final)
15508c2ecf20Sopenharmony_ci				return 0;
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci			/* CCP can't do a zero length sha operation so the
15538c2ecf20Sopenharmony_ci			 * caller must buffer the data.
15548c2ecf20Sopenharmony_ci			 */
15558c2ecf20Sopenharmony_ci			if (sha->msg_bits)
15568c2ecf20Sopenharmony_ci				return -EINVAL;
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci			/* The CCP cannot perform zero-length sha operations
15598c2ecf20Sopenharmony_ci			 * so the caller is required to buffer data for the
15608c2ecf20Sopenharmony_ci			 * final operation. However, a sha operation for a
15618c2ecf20Sopenharmony_ci			 * message with a total length of zero is valid so
15628c2ecf20Sopenharmony_ci			 * known values are required to supply the result.
15638c2ecf20Sopenharmony_ci			 */
15648c2ecf20Sopenharmony_ci			switch (sha->type) {
15658c2ecf20Sopenharmony_ci			case CCP_SHA_TYPE_1:
15668c2ecf20Sopenharmony_ci				sha_zero = sha1_zero_message_hash;
15678c2ecf20Sopenharmony_ci				digest_len = SHA1_DIGEST_SIZE;
15688c2ecf20Sopenharmony_ci				break;
15698c2ecf20Sopenharmony_ci			case CCP_SHA_TYPE_224:
15708c2ecf20Sopenharmony_ci				sha_zero = sha224_zero_message_hash;
15718c2ecf20Sopenharmony_ci				digest_len = SHA224_DIGEST_SIZE;
15728c2ecf20Sopenharmony_ci				break;
15738c2ecf20Sopenharmony_ci			case CCP_SHA_TYPE_256:
15748c2ecf20Sopenharmony_ci				sha_zero = sha256_zero_message_hash;
15758c2ecf20Sopenharmony_ci				digest_len = SHA256_DIGEST_SIZE;
15768c2ecf20Sopenharmony_ci				break;
15778c2ecf20Sopenharmony_ci			default:
15788c2ecf20Sopenharmony_ci				return -EINVAL;
15798c2ecf20Sopenharmony_ci			}
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci			scatterwalk_map_and_copy((void *)sha_zero, sha->ctx, 0,
15828c2ecf20Sopenharmony_ci						 digest_len, 1);
15838c2ecf20Sopenharmony_ci
15848c2ecf20Sopenharmony_ci			return 0;
15858c2ecf20Sopenharmony_ci		}
15868c2ecf20Sopenharmony_ci	}
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_ci	/* Set variables used throughout */
15898c2ecf20Sopenharmony_ci	switch (sha->type) {
15908c2ecf20Sopenharmony_ci	case CCP_SHA_TYPE_1:
15918c2ecf20Sopenharmony_ci		digest_size = SHA1_DIGEST_SIZE;
15928c2ecf20Sopenharmony_ci		init = (void *) ccp_sha1_init;
15938c2ecf20Sopenharmony_ci		ctx_size = SHA1_DIGEST_SIZE;
15948c2ecf20Sopenharmony_ci		sb_count = 1;
15958c2ecf20Sopenharmony_ci		if (cmd_q->ccp->vdata->version != CCP_VERSION(3, 0))
15968c2ecf20Sopenharmony_ci			ooffset = ioffset = CCP_SB_BYTES - SHA1_DIGEST_SIZE;
15978c2ecf20Sopenharmony_ci		else
15988c2ecf20Sopenharmony_ci			ooffset = ioffset = 0;
15998c2ecf20Sopenharmony_ci		break;
16008c2ecf20Sopenharmony_ci	case CCP_SHA_TYPE_224:
16018c2ecf20Sopenharmony_ci		digest_size = SHA224_DIGEST_SIZE;
16028c2ecf20Sopenharmony_ci		init = (void *) ccp_sha224_init;
16038c2ecf20Sopenharmony_ci		ctx_size = SHA256_DIGEST_SIZE;
16048c2ecf20Sopenharmony_ci		sb_count = 1;
16058c2ecf20Sopenharmony_ci		ioffset = 0;
16068c2ecf20Sopenharmony_ci		if (cmd_q->ccp->vdata->version != CCP_VERSION(3, 0))
16078c2ecf20Sopenharmony_ci			ooffset = CCP_SB_BYTES - SHA224_DIGEST_SIZE;
16088c2ecf20Sopenharmony_ci		else
16098c2ecf20Sopenharmony_ci			ooffset = 0;
16108c2ecf20Sopenharmony_ci		break;
16118c2ecf20Sopenharmony_ci	case CCP_SHA_TYPE_256:
16128c2ecf20Sopenharmony_ci		digest_size = SHA256_DIGEST_SIZE;
16138c2ecf20Sopenharmony_ci		init = (void *) ccp_sha256_init;
16148c2ecf20Sopenharmony_ci		ctx_size = SHA256_DIGEST_SIZE;
16158c2ecf20Sopenharmony_ci		sb_count = 1;
16168c2ecf20Sopenharmony_ci		ooffset = ioffset = 0;
16178c2ecf20Sopenharmony_ci		break;
16188c2ecf20Sopenharmony_ci	case CCP_SHA_TYPE_384:
16198c2ecf20Sopenharmony_ci		digest_size = SHA384_DIGEST_SIZE;
16208c2ecf20Sopenharmony_ci		init = (void *) ccp_sha384_init;
16218c2ecf20Sopenharmony_ci		ctx_size = SHA512_DIGEST_SIZE;
16228c2ecf20Sopenharmony_ci		sb_count = 2;
16238c2ecf20Sopenharmony_ci		ioffset = 0;
16248c2ecf20Sopenharmony_ci		ooffset = 2 * CCP_SB_BYTES - SHA384_DIGEST_SIZE;
16258c2ecf20Sopenharmony_ci		break;
16268c2ecf20Sopenharmony_ci	case CCP_SHA_TYPE_512:
16278c2ecf20Sopenharmony_ci		digest_size = SHA512_DIGEST_SIZE;
16288c2ecf20Sopenharmony_ci		init = (void *) ccp_sha512_init;
16298c2ecf20Sopenharmony_ci		ctx_size = SHA512_DIGEST_SIZE;
16308c2ecf20Sopenharmony_ci		sb_count = 2;
16318c2ecf20Sopenharmony_ci		ooffset = ioffset = 0;
16328c2ecf20Sopenharmony_ci		break;
16338c2ecf20Sopenharmony_ci	default:
16348c2ecf20Sopenharmony_ci		ret = -EINVAL;
16358c2ecf20Sopenharmony_ci		goto e_data;
16368c2ecf20Sopenharmony_ci	}
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci	/* For zero-length plaintext the src pointer is ignored;
16398c2ecf20Sopenharmony_ci	 * otherwise both parts must be valid
16408c2ecf20Sopenharmony_ci	 */
16418c2ecf20Sopenharmony_ci	if (sha->src_len && !sha->src)
16428c2ecf20Sopenharmony_ci		return -EINVAL;
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ci	memset(&op, 0, sizeof(op));
16458c2ecf20Sopenharmony_ci	op.cmd_q = cmd_q;
16468c2ecf20Sopenharmony_ci	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
16478c2ecf20Sopenharmony_ci	op.sb_ctx = cmd_q->sb_ctx; /* Pre-allocated */
16488c2ecf20Sopenharmony_ci	op.u.sha.type = sha->type;
16498c2ecf20Sopenharmony_ci	op.u.sha.msg_bits = sha->msg_bits;
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_ci	/* For SHA1/224/256 the context fits in a single (32-byte) SB entry;
16528c2ecf20Sopenharmony_ci	 * SHA384/512 require 2 adjacent SB slots, with the right half in the
16538c2ecf20Sopenharmony_ci	 * first slot, and the left half in the second. Each portion must then
16548c2ecf20Sopenharmony_ci	 * be in little endian format: use the 256-bit byte swap option.
16558c2ecf20Sopenharmony_ci	 */
16568c2ecf20Sopenharmony_ci	ret = ccp_init_dm_workarea(&ctx, cmd_q, sb_count * CCP_SB_BYTES,
16578c2ecf20Sopenharmony_ci				   DMA_BIDIRECTIONAL);
16588c2ecf20Sopenharmony_ci	if (ret)
16598c2ecf20Sopenharmony_ci		return ret;
16608c2ecf20Sopenharmony_ci	if (sha->first) {
16618c2ecf20Sopenharmony_ci		switch (sha->type) {
16628c2ecf20Sopenharmony_ci		case CCP_SHA_TYPE_1:
16638c2ecf20Sopenharmony_ci		case CCP_SHA_TYPE_224:
16648c2ecf20Sopenharmony_ci		case CCP_SHA_TYPE_256:
16658c2ecf20Sopenharmony_ci			memcpy(ctx.address + ioffset, init, ctx_size);
16668c2ecf20Sopenharmony_ci			break;
16678c2ecf20Sopenharmony_ci		case CCP_SHA_TYPE_384:
16688c2ecf20Sopenharmony_ci		case CCP_SHA_TYPE_512:
16698c2ecf20Sopenharmony_ci			memcpy(ctx.address + ctx_size / 2, init,
16708c2ecf20Sopenharmony_ci			       ctx_size / 2);
16718c2ecf20Sopenharmony_ci			memcpy(ctx.address, init + ctx_size / 2,
16728c2ecf20Sopenharmony_ci			       ctx_size / 2);
16738c2ecf20Sopenharmony_ci			break;
16748c2ecf20Sopenharmony_ci		default:
16758c2ecf20Sopenharmony_ci			ret = -EINVAL;
16768c2ecf20Sopenharmony_ci			goto e_ctx;
16778c2ecf20Sopenharmony_ci		}
16788c2ecf20Sopenharmony_ci	} else {
16798c2ecf20Sopenharmony_ci		/* Restore the context */
16808c2ecf20Sopenharmony_ci		ret = ccp_set_dm_area(&ctx, 0, sha->ctx, 0,
16818c2ecf20Sopenharmony_ci				      sb_count * CCP_SB_BYTES);
16828c2ecf20Sopenharmony_ci		if (ret)
16838c2ecf20Sopenharmony_ci			goto e_ctx;
16848c2ecf20Sopenharmony_ci	}
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci	ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
16878c2ecf20Sopenharmony_ci			     CCP_PASSTHRU_BYTESWAP_256BIT);
16888c2ecf20Sopenharmony_ci	if (ret) {
16898c2ecf20Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
16908c2ecf20Sopenharmony_ci		goto e_ctx;
16918c2ecf20Sopenharmony_ci	}
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_ci	if (sha->src) {
16948c2ecf20Sopenharmony_ci		/* Send data to the CCP SHA engine; block_size is set above */
16958c2ecf20Sopenharmony_ci		ret = ccp_init_data(&src, cmd_q, sha->src, sha->src_len,
16968c2ecf20Sopenharmony_ci				    block_size, DMA_TO_DEVICE);
16978c2ecf20Sopenharmony_ci		if (ret)
16988c2ecf20Sopenharmony_ci			goto e_ctx;
16998c2ecf20Sopenharmony_ci
17008c2ecf20Sopenharmony_ci		while (src.sg_wa.bytes_left) {
17018c2ecf20Sopenharmony_ci			ccp_prepare_data(&src, NULL, &op, block_size, false);
17028c2ecf20Sopenharmony_ci			if (sha->final && !src.sg_wa.bytes_left)
17038c2ecf20Sopenharmony_ci				op.eom = 1;
17048c2ecf20Sopenharmony_ci
17058c2ecf20Sopenharmony_ci			ret = cmd_q->ccp->vdata->perform->sha(&op);
17068c2ecf20Sopenharmony_ci			if (ret) {
17078c2ecf20Sopenharmony_ci				cmd->engine_error = cmd_q->cmd_error;
17088c2ecf20Sopenharmony_ci				goto e_data;
17098c2ecf20Sopenharmony_ci			}
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci			ccp_process_data(&src, NULL, &op);
17128c2ecf20Sopenharmony_ci		}
17138c2ecf20Sopenharmony_ci	} else {
17148c2ecf20Sopenharmony_ci		op.eom = 1;
17158c2ecf20Sopenharmony_ci		ret = cmd_q->ccp->vdata->perform->sha(&op);
17168c2ecf20Sopenharmony_ci		if (ret) {
17178c2ecf20Sopenharmony_ci			cmd->engine_error = cmd_q->cmd_error;
17188c2ecf20Sopenharmony_ci			goto e_data;
17198c2ecf20Sopenharmony_ci		}
17208c2ecf20Sopenharmony_ci	}
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_ci	/* Retrieve the SHA context - convert from LE to BE using
17238c2ecf20Sopenharmony_ci	 * 32-byte (256-bit) byteswapping to BE
17248c2ecf20Sopenharmony_ci	 */
17258c2ecf20Sopenharmony_ci	ret = ccp_copy_from_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
17268c2ecf20Sopenharmony_ci			       CCP_PASSTHRU_BYTESWAP_256BIT);
17278c2ecf20Sopenharmony_ci	if (ret) {
17288c2ecf20Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
17298c2ecf20Sopenharmony_ci		goto e_data;
17308c2ecf20Sopenharmony_ci	}
17318c2ecf20Sopenharmony_ci
17328c2ecf20Sopenharmony_ci	if (sha->final) {
17338c2ecf20Sopenharmony_ci		/* Finishing up, so get the digest */
17348c2ecf20Sopenharmony_ci		switch (sha->type) {
17358c2ecf20Sopenharmony_ci		case CCP_SHA_TYPE_1:
17368c2ecf20Sopenharmony_ci		case CCP_SHA_TYPE_224:
17378c2ecf20Sopenharmony_ci		case CCP_SHA_TYPE_256:
17388c2ecf20Sopenharmony_ci			ccp_get_dm_area(&ctx, ooffset,
17398c2ecf20Sopenharmony_ci					sha->ctx, 0,
17408c2ecf20Sopenharmony_ci					digest_size);
17418c2ecf20Sopenharmony_ci			break;
17428c2ecf20Sopenharmony_ci		case CCP_SHA_TYPE_384:
17438c2ecf20Sopenharmony_ci		case CCP_SHA_TYPE_512:
17448c2ecf20Sopenharmony_ci			ccp_get_dm_area(&ctx, 0,
17458c2ecf20Sopenharmony_ci					sha->ctx, LSB_ITEM_SIZE - ooffset,
17468c2ecf20Sopenharmony_ci					LSB_ITEM_SIZE);
17478c2ecf20Sopenharmony_ci			ccp_get_dm_area(&ctx, LSB_ITEM_SIZE + ooffset,
17488c2ecf20Sopenharmony_ci					sha->ctx, 0,
17498c2ecf20Sopenharmony_ci					LSB_ITEM_SIZE - ooffset);
17508c2ecf20Sopenharmony_ci			break;
17518c2ecf20Sopenharmony_ci		default:
17528c2ecf20Sopenharmony_ci			ret = -EINVAL;
17538c2ecf20Sopenharmony_ci			goto e_data;
17548c2ecf20Sopenharmony_ci		}
17558c2ecf20Sopenharmony_ci	} else {
17568c2ecf20Sopenharmony_ci		/* Stash the context */
17578c2ecf20Sopenharmony_ci		ccp_get_dm_area(&ctx, 0, sha->ctx, 0,
17588c2ecf20Sopenharmony_ci				sb_count * CCP_SB_BYTES);
17598c2ecf20Sopenharmony_ci	}
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_ci	if (sha->final && sha->opad) {
17628c2ecf20Sopenharmony_ci		/* HMAC operation, recursively perform final SHA */
17638c2ecf20Sopenharmony_ci		struct ccp_cmd hmac_cmd;
17648c2ecf20Sopenharmony_ci		struct scatterlist sg;
17658c2ecf20Sopenharmony_ci		u8 *hmac_buf;
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_ci		if (sha->opad_len != block_size) {
17688c2ecf20Sopenharmony_ci			ret = -EINVAL;
17698c2ecf20Sopenharmony_ci			goto e_data;
17708c2ecf20Sopenharmony_ci		}
17718c2ecf20Sopenharmony_ci
17728c2ecf20Sopenharmony_ci		hmac_buf = kmalloc(block_size + digest_size, GFP_KERNEL);
17738c2ecf20Sopenharmony_ci		if (!hmac_buf) {
17748c2ecf20Sopenharmony_ci			ret = -ENOMEM;
17758c2ecf20Sopenharmony_ci			goto e_data;
17768c2ecf20Sopenharmony_ci		}
17778c2ecf20Sopenharmony_ci		sg_init_one(&sg, hmac_buf, block_size + digest_size);
17788c2ecf20Sopenharmony_ci
17798c2ecf20Sopenharmony_ci		scatterwalk_map_and_copy(hmac_buf, sha->opad, 0, block_size, 0);
17808c2ecf20Sopenharmony_ci		switch (sha->type) {
17818c2ecf20Sopenharmony_ci		case CCP_SHA_TYPE_1:
17828c2ecf20Sopenharmony_ci		case CCP_SHA_TYPE_224:
17838c2ecf20Sopenharmony_ci		case CCP_SHA_TYPE_256:
17848c2ecf20Sopenharmony_ci			memcpy(hmac_buf + block_size,
17858c2ecf20Sopenharmony_ci			       ctx.address + ooffset,
17868c2ecf20Sopenharmony_ci			       digest_size);
17878c2ecf20Sopenharmony_ci			break;
17888c2ecf20Sopenharmony_ci		case CCP_SHA_TYPE_384:
17898c2ecf20Sopenharmony_ci		case CCP_SHA_TYPE_512:
17908c2ecf20Sopenharmony_ci			memcpy(hmac_buf + block_size,
17918c2ecf20Sopenharmony_ci			       ctx.address + LSB_ITEM_SIZE + ooffset,
17928c2ecf20Sopenharmony_ci			       LSB_ITEM_SIZE);
17938c2ecf20Sopenharmony_ci			memcpy(hmac_buf + block_size +
17948c2ecf20Sopenharmony_ci			       (LSB_ITEM_SIZE - ooffset),
17958c2ecf20Sopenharmony_ci			       ctx.address,
17968c2ecf20Sopenharmony_ci			       LSB_ITEM_SIZE);
17978c2ecf20Sopenharmony_ci			break;
17988c2ecf20Sopenharmony_ci		default:
17998c2ecf20Sopenharmony_ci			kfree(hmac_buf);
18008c2ecf20Sopenharmony_ci			ret = -EINVAL;
18018c2ecf20Sopenharmony_ci			goto e_data;
18028c2ecf20Sopenharmony_ci		}
18038c2ecf20Sopenharmony_ci
18048c2ecf20Sopenharmony_ci		memset(&hmac_cmd, 0, sizeof(hmac_cmd));
18058c2ecf20Sopenharmony_ci		hmac_cmd.engine = CCP_ENGINE_SHA;
18068c2ecf20Sopenharmony_ci		hmac_cmd.u.sha.type = sha->type;
18078c2ecf20Sopenharmony_ci		hmac_cmd.u.sha.ctx = sha->ctx;
18088c2ecf20Sopenharmony_ci		hmac_cmd.u.sha.ctx_len = sha->ctx_len;
18098c2ecf20Sopenharmony_ci		hmac_cmd.u.sha.src = &sg;
18108c2ecf20Sopenharmony_ci		hmac_cmd.u.sha.src_len = block_size + digest_size;
18118c2ecf20Sopenharmony_ci		hmac_cmd.u.sha.opad = NULL;
18128c2ecf20Sopenharmony_ci		hmac_cmd.u.sha.opad_len = 0;
18138c2ecf20Sopenharmony_ci		hmac_cmd.u.sha.first = 1;
18148c2ecf20Sopenharmony_ci		hmac_cmd.u.sha.final = 1;
18158c2ecf20Sopenharmony_ci		hmac_cmd.u.sha.msg_bits = (block_size + digest_size) << 3;
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_ci		ret = ccp_run_sha_cmd(cmd_q, &hmac_cmd);
18188c2ecf20Sopenharmony_ci		if (ret)
18198c2ecf20Sopenharmony_ci			cmd->engine_error = hmac_cmd.engine_error;
18208c2ecf20Sopenharmony_ci
18218c2ecf20Sopenharmony_ci		kfree(hmac_buf);
18228c2ecf20Sopenharmony_ci	}
18238c2ecf20Sopenharmony_ci
18248c2ecf20Sopenharmony_cie_data:
18258c2ecf20Sopenharmony_ci	if (sha->src)
18268c2ecf20Sopenharmony_ci		ccp_free_data(&src, cmd_q);
18278c2ecf20Sopenharmony_ci
18288c2ecf20Sopenharmony_cie_ctx:
18298c2ecf20Sopenharmony_ci	ccp_dm_free(&ctx);
18308c2ecf20Sopenharmony_ci
18318c2ecf20Sopenharmony_ci	return ret;
18328c2ecf20Sopenharmony_ci}
18338c2ecf20Sopenharmony_ci
18348c2ecf20Sopenharmony_cistatic noinline_for_stack int
18358c2ecf20Sopenharmony_ciccp_run_rsa_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
18368c2ecf20Sopenharmony_ci{
18378c2ecf20Sopenharmony_ci	struct ccp_rsa_engine *rsa = &cmd->u.rsa;
18388c2ecf20Sopenharmony_ci	struct ccp_dm_workarea exp, src, dst;
18398c2ecf20Sopenharmony_ci	struct ccp_op op;
18408c2ecf20Sopenharmony_ci	unsigned int sb_count, i_len, o_len;
18418c2ecf20Sopenharmony_ci	int ret;
18428c2ecf20Sopenharmony_ci
18438c2ecf20Sopenharmony_ci	/* Check against the maximum allowable size, in bits */
18448c2ecf20Sopenharmony_ci	if (rsa->key_size > cmd_q->ccp->vdata->rsamax)
18458c2ecf20Sopenharmony_ci		return -EINVAL;
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_ci	if (!rsa->exp || !rsa->mod || !rsa->src || !rsa->dst)
18488c2ecf20Sopenharmony_ci		return -EINVAL;
18498c2ecf20Sopenharmony_ci
18508c2ecf20Sopenharmony_ci	memset(&op, 0, sizeof(op));
18518c2ecf20Sopenharmony_ci	op.cmd_q = cmd_q;
18528c2ecf20Sopenharmony_ci	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
18538c2ecf20Sopenharmony_ci
18548c2ecf20Sopenharmony_ci	/* The RSA modulus must precede the message being acted upon, so
18558c2ecf20Sopenharmony_ci	 * it must be copied to a DMA area where the message and the
18568c2ecf20Sopenharmony_ci	 * modulus can be concatenated.  Therefore the input buffer
18578c2ecf20Sopenharmony_ci	 * length required is twice the output buffer length (which
18588c2ecf20Sopenharmony_ci	 * must be a multiple of 256-bits).  Compute o_len, i_len in bytes.
18598c2ecf20Sopenharmony_ci	 * Buffer sizes must be a multiple of 32 bytes; rounding up may be
18608c2ecf20Sopenharmony_ci	 * required.
18618c2ecf20Sopenharmony_ci	 */
18628c2ecf20Sopenharmony_ci	o_len = 32 * ((rsa->key_size + 255) / 256);
18638c2ecf20Sopenharmony_ci	i_len = o_len * 2;
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci	sb_count = 0;
18668c2ecf20Sopenharmony_ci	if (cmd_q->ccp->vdata->version < CCP_VERSION(5, 0)) {
18678c2ecf20Sopenharmony_ci		/* sb_count is the number of storage block slots required
18688c2ecf20Sopenharmony_ci		 * for the modulus.
18698c2ecf20Sopenharmony_ci		 */
18708c2ecf20Sopenharmony_ci		sb_count = o_len / CCP_SB_BYTES;
18718c2ecf20Sopenharmony_ci		op.sb_key = cmd_q->ccp->vdata->perform->sballoc(cmd_q,
18728c2ecf20Sopenharmony_ci								sb_count);
18738c2ecf20Sopenharmony_ci		if (!op.sb_key)
18748c2ecf20Sopenharmony_ci			return -EIO;
18758c2ecf20Sopenharmony_ci	} else {
18768c2ecf20Sopenharmony_ci		/* A version 5 device allows a modulus size that will not fit
18778c2ecf20Sopenharmony_ci		 * in the LSB, so the command will transfer it from memory.
18788c2ecf20Sopenharmony_ci		 * Set the sb key to the default, even though it's not used.
18798c2ecf20Sopenharmony_ci		 */
18808c2ecf20Sopenharmony_ci		op.sb_key = cmd_q->sb_key;
18818c2ecf20Sopenharmony_ci	}
18828c2ecf20Sopenharmony_ci
18838c2ecf20Sopenharmony_ci	/* The RSA exponent must be in little endian format. Reverse its
18848c2ecf20Sopenharmony_ci	 * byte order.
18858c2ecf20Sopenharmony_ci	 */
18868c2ecf20Sopenharmony_ci	ret = ccp_init_dm_workarea(&exp, cmd_q, o_len, DMA_TO_DEVICE);
18878c2ecf20Sopenharmony_ci	if (ret)
18888c2ecf20Sopenharmony_ci		goto e_sb;
18898c2ecf20Sopenharmony_ci
18908c2ecf20Sopenharmony_ci	ret = ccp_reverse_set_dm_area(&exp, 0, rsa->exp, 0, rsa->exp_len);
18918c2ecf20Sopenharmony_ci	if (ret)
18928c2ecf20Sopenharmony_ci		goto e_exp;
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ci	if (cmd_q->ccp->vdata->version < CCP_VERSION(5, 0)) {
18958c2ecf20Sopenharmony_ci		/* Copy the exponent to the local storage block, using
18968c2ecf20Sopenharmony_ci		 * as many 32-byte blocks as were allocated above. It's
18978c2ecf20Sopenharmony_ci		 * already little endian, so no further change is required.
18988c2ecf20Sopenharmony_ci		 */
18998c2ecf20Sopenharmony_ci		ret = ccp_copy_to_sb(cmd_q, &exp, op.jobid, op.sb_key,
19008c2ecf20Sopenharmony_ci				     CCP_PASSTHRU_BYTESWAP_NOOP);
19018c2ecf20Sopenharmony_ci		if (ret) {
19028c2ecf20Sopenharmony_ci			cmd->engine_error = cmd_q->cmd_error;
19038c2ecf20Sopenharmony_ci			goto e_exp;
19048c2ecf20Sopenharmony_ci		}
19058c2ecf20Sopenharmony_ci	} else {
19068c2ecf20Sopenharmony_ci		/* The exponent can be retrieved from memory via DMA. */
19078c2ecf20Sopenharmony_ci		op.exp.u.dma.address = exp.dma.address;
19088c2ecf20Sopenharmony_ci		op.exp.u.dma.offset = 0;
19098c2ecf20Sopenharmony_ci	}
19108c2ecf20Sopenharmony_ci
19118c2ecf20Sopenharmony_ci	/* Concatenate the modulus and the message. Both the modulus and
19128c2ecf20Sopenharmony_ci	 * the operands must be in little endian format.  Since the input
19138c2ecf20Sopenharmony_ci	 * is in big endian format it must be converted.
19148c2ecf20Sopenharmony_ci	 */
19158c2ecf20Sopenharmony_ci	ret = ccp_init_dm_workarea(&src, cmd_q, i_len, DMA_TO_DEVICE);
19168c2ecf20Sopenharmony_ci	if (ret)
19178c2ecf20Sopenharmony_ci		goto e_exp;
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci	ret = ccp_reverse_set_dm_area(&src, 0, rsa->mod, 0, rsa->mod_len);
19208c2ecf20Sopenharmony_ci	if (ret)
19218c2ecf20Sopenharmony_ci		goto e_src;
19228c2ecf20Sopenharmony_ci	ret = ccp_reverse_set_dm_area(&src, o_len, rsa->src, 0, rsa->src_len);
19238c2ecf20Sopenharmony_ci	if (ret)
19248c2ecf20Sopenharmony_ci		goto e_src;
19258c2ecf20Sopenharmony_ci
19268c2ecf20Sopenharmony_ci	/* Prepare the output area for the operation */
19278c2ecf20Sopenharmony_ci	ret = ccp_init_dm_workarea(&dst, cmd_q, o_len, DMA_FROM_DEVICE);
19288c2ecf20Sopenharmony_ci	if (ret)
19298c2ecf20Sopenharmony_ci		goto e_src;
19308c2ecf20Sopenharmony_ci
19318c2ecf20Sopenharmony_ci	op.soc = 1;
19328c2ecf20Sopenharmony_ci	op.src.u.dma.address = src.dma.address;
19338c2ecf20Sopenharmony_ci	op.src.u.dma.offset = 0;
19348c2ecf20Sopenharmony_ci	op.src.u.dma.length = i_len;
19358c2ecf20Sopenharmony_ci	op.dst.u.dma.address = dst.dma.address;
19368c2ecf20Sopenharmony_ci	op.dst.u.dma.offset = 0;
19378c2ecf20Sopenharmony_ci	op.dst.u.dma.length = o_len;
19388c2ecf20Sopenharmony_ci
19398c2ecf20Sopenharmony_ci	op.u.rsa.mod_size = rsa->key_size;
19408c2ecf20Sopenharmony_ci	op.u.rsa.input_len = i_len;
19418c2ecf20Sopenharmony_ci
19428c2ecf20Sopenharmony_ci	ret = cmd_q->ccp->vdata->perform->rsa(&op);
19438c2ecf20Sopenharmony_ci	if (ret) {
19448c2ecf20Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
19458c2ecf20Sopenharmony_ci		goto e_dst;
19468c2ecf20Sopenharmony_ci	}
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_ci	ccp_reverse_get_dm_area(&dst, 0, rsa->dst, 0, rsa->mod_len);
19498c2ecf20Sopenharmony_ci
19508c2ecf20Sopenharmony_cie_dst:
19518c2ecf20Sopenharmony_ci	ccp_dm_free(&dst);
19528c2ecf20Sopenharmony_ci
19538c2ecf20Sopenharmony_cie_src:
19548c2ecf20Sopenharmony_ci	ccp_dm_free(&src);
19558c2ecf20Sopenharmony_ci
19568c2ecf20Sopenharmony_cie_exp:
19578c2ecf20Sopenharmony_ci	ccp_dm_free(&exp);
19588c2ecf20Sopenharmony_ci
19598c2ecf20Sopenharmony_cie_sb:
19608c2ecf20Sopenharmony_ci	if (sb_count)
19618c2ecf20Sopenharmony_ci		cmd_q->ccp->vdata->perform->sbfree(cmd_q, op.sb_key, sb_count);
19628c2ecf20Sopenharmony_ci
19638c2ecf20Sopenharmony_ci	return ret;
19648c2ecf20Sopenharmony_ci}
19658c2ecf20Sopenharmony_ci
19668c2ecf20Sopenharmony_cistatic noinline_for_stack int
19678c2ecf20Sopenharmony_ciccp_run_passthru_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
19688c2ecf20Sopenharmony_ci{
19698c2ecf20Sopenharmony_ci	struct ccp_passthru_engine *pt = &cmd->u.passthru;
19708c2ecf20Sopenharmony_ci	struct ccp_dm_workarea mask;
19718c2ecf20Sopenharmony_ci	struct ccp_data src, dst;
19728c2ecf20Sopenharmony_ci	struct ccp_op op;
19738c2ecf20Sopenharmony_ci	bool in_place = false;
19748c2ecf20Sopenharmony_ci	unsigned int i;
19758c2ecf20Sopenharmony_ci	int ret = 0;
19768c2ecf20Sopenharmony_ci
19778c2ecf20Sopenharmony_ci	if (!pt->final && (pt->src_len & (CCP_PASSTHRU_BLOCKSIZE - 1)))
19788c2ecf20Sopenharmony_ci		return -EINVAL;
19798c2ecf20Sopenharmony_ci
19808c2ecf20Sopenharmony_ci	if (!pt->src || !pt->dst)
19818c2ecf20Sopenharmony_ci		return -EINVAL;
19828c2ecf20Sopenharmony_ci
19838c2ecf20Sopenharmony_ci	if (pt->bit_mod != CCP_PASSTHRU_BITWISE_NOOP) {
19848c2ecf20Sopenharmony_ci		if (pt->mask_len != CCP_PASSTHRU_MASKSIZE)
19858c2ecf20Sopenharmony_ci			return -EINVAL;
19868c2ecf20Sopenharmony_ci		if (!pt->mask)
19878c2ecf20Sopenharmony_ci			return -EINVAL;
19888c2ecf20Sopenharmony_ci	}
19898c2ecf20Sopenharmony_ci
19908c2ecf20Sopenharmony_ci	BUILD_BUG_ON(CCP_PASSTHRU_SB_COUNT != 1);
19918c2ecf20Sopenharmony_ci
19928c2ecf20Sopenharmony_ci	memset(&op, 0, sizeof(op));
19938c2ecf20Sopenharmony_ci	op.cmd_q = cmd_q;
19948c2ecf20Sopenharmony_ci	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
19958c2ecf20Sopenharmony_ci
19968c2ecf20Sopenharmony_ci	if (pt->bit_mod != CCP_PASSTHRU_BITWISE_NOOP) {
19978c2ecf20Sopenharmony_ci		/* Load the mask */
19988c2ecf20Sopenharmony_ci		op.sb_key = cmd_q->sb_key;
19998c2ecf20Sopenharmony_ci
20008c2ecf20Sopenharmony_ci		ret = ccp_init_dm_workarea(&mask, cmd_q,
20018c2ecf20Sopenharmony_ci					   CCP_PASSTHRU_SB_COUNT *
20028c2ecf20Sopenharmony_ci					   CCP_SB_BYTES,
20038c2ecf20Sopenharmony_ci					   DMA_TO_DEVICE);
20048c2ecf20Sopenharmony_ci		if (ret)
20058c2ecf20Sopenharmony_ci			return ret;
20068c2ecf20Sopenharmony_ci
20078c2ecf20Sopenharmony_ci		ret = ccp_set_dm_area(&mask, 0, pt->mask, 0, pt->mask_len);
20088c2ecf20Sopenharmony_ci		if (ret)
20098c2ecf20Sopenharmony_ci			goto e_mask;
20108c2ecf20Sopenharmony_ci		ret = ccp_copy_to_sb(cmd_q, &mask, op.jobid, op.sb_key,
20118c2ecf20Sopenharmony_ci				     CCP_PASSTHRU_BYTESWAP_NOOP);
20128c2ecf20Sopenharmony_ci		if (ret) {
20138c2ecf20Sopenharmony_ci			cmd->engine_error = cmd_q->cmd_error;
20148c2ecf20Sopenharmony_ci			goto e_mask;
20158c2ecf20Sopenharmony_ci		}
20168c2ecf20Sopenharmony_ci	}
20178c2ecf20Sopenharmony_ci
20188c2ecf20Sopenharmony_ci	/* Prepare the input and output data workareas. For in-place
20198c2ecf20Sopenharmony_ci	 * operations we need to set the dma direction to BIDIRECTIONAL
20208c2ecf20Sopenharmony_ci	 * and copy the src workarea to the dst workarea.
20218c2ecf20Sopenharmony_ci	 */
20228c2ecf20Sopenharmony_ci	if (sg_virt(pt->src) == sg_virt(pt->dst))
20238c2ecf20Sopenharmony_ci		in_place = true;
20248c2ecf20Sopenharmony_ci
20258c2ecf20Sopenharmony_ci	ret = ccp_init_data(&src, cmd_q, pt->src, pt->src_len,
20268c2ecf20Sopenharmony_ci			    CCP_PASSTHRU_MASKSIZE,
20278c2ecf20Sopenharmony_ci			    in_place ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE);
20288c2ecf20Sopenharmony_ci	if (ret)
20298c2ecf20Sopenharmony_ci		goto e_mask;
20308c2ecf20Sopenharmony_ci
20318c2ecf20Sopenharmony_ci	if (in_place) {
20328c2ecf20Sopenharmony_ci		dst = src;
20338c2ecf20Sopenharmony_ci	} else {
20348c2ecf20Sopenharmony_ci		ret = ccp_init_data(&dst, cmd_q, pt->dst, pt->src_len,
20358c2ecf20Sopenharmony_ci				    CCP_PASSTHRU_MASKSIZE, DMA_FROM_DEVICE);
20368c2ecf20Sopenharmony_ci		if (ret)
20378c2ecf20Sopenharmony_ci			goto e_src;
20388c2ecf20Sopenharmony_ci	}
20398c2ecf20Sopenharmony_ci
20408c2ecf20Sopenharmony_ci	/* Send data to the CCP Passthru engine
20418c2ecf20Sopenharmony_ci	 *   Because the CCP engine works on a single source and destination
20428c2ecf20Sopenharmony_ci	 *   dma address at a time, each entry in the source scatterlist
20438c2ecf20Sopenharmony_ci	 *   (after the dma_map_sg call) must be less than or equal to the
20448c2ecf20Sopenharmony_ci	 *   (remaining) length in the destination scatterlist entry and the
20458c2ecf20Sopenharmony_ci	 *   length must be a multiple of CCP_PASSTHRU_BLOCKSIZE
20468c2ecf20Sopenharmony_ci	 */
20478c2ecf20Sopenharmony_ci	dst.sg_wa.sg_used = 0;
20488c2ecf20Sopenharmony_ci	for (i = 1; i <= src.sg_wa.dma_count; i++) {
20498c2ecf20Sopenharmony_ci		if (!dst.sg_wa.sg ||
20508c2ecf20Sopenharmony_ci		    (sg_dma_len(dst.sg_wa.sg) < sg_dma_len(src.sg_wa.sg))) {
20518c2ecf20Sopenharmony_ci			ret = -EINVAL;
20528c2ecf20Sopenharmony_ci			goto e_dst;
20538c2ecf20Sopenharmony_ci		}
20548c2ecf20Sopenharmony_ci
20558c2ecf20Sopenharmony_ci		if (i == src.sg_wa.dma_count) {
20568c2ecf20Sopenharmony_ci			op.eom = 1;
20578c2ecf20Sopenharmony_ci			op.soc = 1;
20588c2ecf20Sopenharmony_ci		}
20598c2ecf20Sopenharmony_ci
20608c2ecf20Sopenharmony_ci		op.src.type = CCP_MEMTYPE_SYSTEM;
20618c2ecf20Sopenharmony_ci		op.src.u.dma.address = sg_dma_address(src.sg_wa.sg);
20628c2ecf20Sopenharmony_ci		op.src.u.dma.offset = 0;
20638c2ecf20Sopenharmony_ci		op.src.u.dma.length = sg_dma_len(src.sg_wa.sg);
20648c2ecf20Sopenharmony_ci
20658c2ecf20Sopenharmony_ci		op.dst.type = CCP_MEMTYPE_SYSTEM;
20668c2ecf20Sopenharmony_ci		op.dst.u.dma.address = sg_dma_address(dst.sg_wa.sg);
20678c2ecf20Sopenharmony_ci		op.dst.u.dma.offset = dst.sg_wa.sg_used;
20688c2ecf20Sopenharmony_ci		op.dst.u.dma.length = op.src.u.dma.length;
20698c2ecf20Sopenharmony_ci
20708c2ecf20Sopenharmony_ci		ret = cmd_q->ccp->vdata->perform->passthru(&op);
20718c2ecf20Sopenharmony_ci		if (ret) {
20728c2ecf20Sopenharmony_ci			cmd->engine_error = cmd_q->cmd_error;
20738c2ecf20Sopenharmony_ci			goto e_dst;
20748c2ecf20Sopenharmony_ci		}
20758c2ecf20Sopenharmony_ci
20768c2ecf20Sopenharmony_ci		dst.sg_wa.sg_used += sg_dma_len(src.sg_wa.sg);
20778c2ecf20Sopenharmony_ci		if (dst.sg_wa.sg_used == sg_dma_len(dst.sg_wa.sg)) {
20788c2ecf20Sopenharmony_ci			dst.sg_wa.sg = sg_next(dst.sg_wa.sg);
20798c2ecf20Sopenharmony_ci			dst.sg_wa.sg_used = 0;
20808c2ecf20Sopenharmony_ci		}
20818c2ecf20Sopenharmony_ci		src.sg_wa.sg = sg_next(src.sg_wa.sg);
20828c2ecf20Sopenharmony_ci	}
20838c2ecf20Sopenharmony_ci
20848c2ecf20Sopenharmony_cie_dst:
20858c2ecf20Sopenharmony_ci	if (!in_place)
20868c2ecf20Sopenharmony_ci		ccp_free_data(&dst, cmd_q);
20878c2ecf20Sopenharmony_ci
20888c2ecf20Sopenharmony_cie_src:
20898c2ecf20Sopenharmony_ci	ccp_free_data(&src, cmd_q);
20908c2ecf20Sopenharmony_ci
20918c2ecf20Sopenharmony_cie_mask:
20928c2ecf20Sopenharmony_ci	if (pt->bit_mod != CCP_PASSTHRU_BITWISE_NOOP)
20938c2ecf20Sopenharmony_ci		ccp_dm_free(&mask);
20948c2ecf20Sopenharmony_ci
20958c2ecf20Sopenharmony_ci	return ret;
20968c2ecf20Sopenharmony_ci}
20978c2ecf20Sopenharmony_ci
20988c2ecf20Sopenharmony_cistatic noinline_for_stack int
20998c2ecf20Sopenharmony_ciccp_run_passthru_nomap_cmd(struct ccp_cmd_queue *cmd_q,
21008c2ecf20Sopenharmony_ci				      struct ccp_cmd *cmd)
21018c2ecf20Sopenharmony_ci{
21028c2ecf20Sopenharmony_ci	struct ccp_passthru_nomap_engine *pt = &cmd->u.passthru_nomap;
21038c2ecf20Sopenharmony_ci	struct ccp_dm_workarea mask;
21048c2ecf20Sopenharmony_ci	struct ccp_op op;
21058c2ecf20Sopenharmony_ci	int ret;
21068c2ecf20Sopenharmony_ci
21078c2ecf20Sopenharmony_ci	if (!pt->final && (pt->src_len & (CCP_PASSTHRU_BLOCKSIZE - 1)))
21088c2ecf20Sopenharmony_ci		return -EINVAL;
21098c2ecf20Sopenharmony_ci
21108c2ecf20Sopenharmony_ci	if (!pt->src_dma || !pt->dst_dma)
21118c2ecf20Sopenharmony_ci		return -EINVAL;
21128c2ecf20Sopenharmony_ci
21138c2ecf20Sopenharmony_ci	if (pt->bit_mod != CCP_PASSTHRU_BITWISE_NOOP) {
21148c2ecf20Sopenharmony_ci		if (pt->mask_len != CCP_PASSTHRU_MASKSIZE)
21158c2ecf20Sopenharmony_ci			return -EINVAL;
21168c2ecf20Sopenharmony_ci		if (!pt->mask)
21178c2ecf20Sopenharmony_ci			return -EINVAL;
21188c2ecf20Sopenharmony_ci	}
21198c2ecf20Sopenharmony_ci
21208c2ecf20Sopenharmony_ci	BUILD_BUG_ON(CCP_PASSTHRU_SB_COUNT != 1);
21218c2ecf20Sopenharmony_ci
21228c2ecf20Sopenharmony_ci	memset(&op, 0, sizeof(op));
21238c2ecf20Sopenharmony_ci	op.cmd_q = cmd_q;
21248c2ecf20Sopenharmony_ci	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
21258c2ecf20Sopenharmony_ci
21268c2ecf20Sopenharmony_ci	if (pt->bit_mod != CCP_PASSTHRU_BITWISE_NOOP) {
21278c2ecf20Sopenharmony_ci		/* Load the mask */
21288c2ecf20Sopenharmony_ci		op.sb_key = cmd_q->sb_key;
21298c2ecf20Sopenharmony_ci
21308c2ecf20Sopenharmony_ci		mask.length = pt->mask_len;
21318c2ecf20Sopenharmony_ci		mask.dma.address = pt->mask;
21328c2ecf20Sopenharmony_ci		mask.dma.length = pt->mask_len;
21338c2ecf20Sopenharmony_ci
21348c2ecf20Sopenharmony_ci		ret = ccp_copy_to_sb(cmd_q, &mask, op.jobid, op.sb_key,
21358c2ecf20Sopenharmony_ci				     CCP_PASSTHRU_BYTESWAP_NOOP);
21368c2ecf20Sopenharmony_ci		if (ret) {
21378c2ecf20Sopenharmony_ci			cmd->engine_error = cmd_q->cmd_error;
21388c2ecf20Sopenharmony_ci			return ret;
21398c2ecf20Sopenharmony_ci		}
21408c2ecf20Sopenharmony_ci	}
21418c2ecf20Sopenharmony_ci
21428c2ecf20Sopenharmony_ci	/* Send data to the CCP Passthru engine */
21438c2ecf20Sopenharmony_ci	op.eom = 1;
21448c2ecf20Sopenharmony_ci	op.soc = 1;
21458c2ecf20Sopenharmony_ci
21468c2ecf20Sopenharmony_ci	op.src.type = CCP_MEMTYPE_SYSTEM;
21478c2ecf20Sopenharmony_ci	op.src.u.dma.address = pt->src_dma;
21488c2ecf20Sopenharmony_ci	op.src.u.dma.offset = 0;
21498c2ecf20Sopenharmony_ci	op.src.u.dma.length = pt->src_len;
21508c2ecf20Sopenharmony_ci
21518c2ecf20Sopenharmony_ci	op.dst.type = CCP_MEMTYPE_SYSTEM;
21528c2ecf20Sopenharmony_ci	op.dst.u.dma.address = pt->dst_dma;
21538c2ecf20Sopenharmony_ci	op.dst.u.dma.offset = 0;
21548c2ecf20Sopenharmony_ci	op.dst.u.dma.length = pt->src_len;
21558c2ecf20Sopenharmony_ci
21568c2ecf20Sopenharmony_ci	ret = cmd_q->ccp->vdata->perform->passthru(&op);
21578c2ecf20Sopenharmony_ci	if (ret)
21588c2ecf20Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
21598c2ecf20Sopenharmony_ci
21608c2ecf20Sopenharmony_ci	return ret;
21618c2ecf20Sopenharmony_ci}
21628c2ecf20Sopenharmony_ci
21638c2ecf20Sopenharmony_cistatic int ccp_run_ecc_mm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
21648c2ecf20Sopenharmony_ci{
21658c2ecf20Sopenharmony_ci	struct ccp_ecc_engine *ecc = &cmd->u.ecc;
21668c2ecf20Sopenharmony_ci	struct ccp_dm_workarea src, dst;
21678c2ecf20Sopenharmony_ci	struct ccp_op op;
21688c2ecf20Sopenharmony_ci	int ret;
21698c2ecf20Sopenharmony_ci	u8 *save;
21708c2ecf20Sopenharmony_ci
21718c2ecf20Sopenharmony_ci	if (!ecc->u.mm.operand_1 ||
21728c2ecf20Sopenharmony_ci	    (ecc->u.mm.operand_1_len > CCP_ECC_MODULUS_BYTES))
21738c2ecf20Sopenharmony_ci		return -EINVAL;
21748c2ecf20Sopenharmony_ci
21758c2ecf20Sopenharmony_ci	if (ecc->function != CCP_ECC_FUNCTION_MINV_384BIT)
21768c2ecf20Sopenharmony_ci		if (!ecc->u.mm.operand_2 ||
21778c2ecf20Sopenharmony_ci		    (ecc->u.mm.operand_2_len > CCP_ECC_MODULUS_BYTES))
21788c2ecf20Sopenharmony_ci			return -EINVAL;
21798c2ecf20Sopenharmony_ci
21808c2ecf20Sopenharmony_ci	if (!ecc->u.mm.result ||
21818c2ecf20Sopenharmony_ci	    (ecc->u.mm.result_len < CCP_ECC_MODULUS_BYTES))
21828c2ecf20Sopenharmony_ci		return -EINVAL;
21838c2ecf20Sopenharmony_ci
21848c2ecf20Sopenharmony_ci	memset(&op, 0, sizeof(op));
21858c2ecf20Sopenharmony_ci	op.cmd_q = cmd_q;
21868c2ecf20Sopenharmony_ci	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
21878c2ecf20Sopenharmony_ci
21888c2ecf20Sopenharmony_ci	/* Concatenate the modulus and the operands. Both the modulus and
21898c2ecf20Sopenharmony_ci	 * the operands must be in little endian format.  Since the input
21908c2ecf20Sopenharmony_ci	 * is in big endian format it must be converted and placed in a
21918c2ecf20Sopenharmony_ci	 * fixed length buffer.
21928c2ecf20Sopenharmony_ci	 */
21938c2ecf20Sopenharmony_ci	ret = ccp_init_dm_workarea(&src, cmd_q, CCP_ECC_SRC_BUF_SIZE,
21948c2ecf20Sopenharmony_ci				   DMA_TO_DEVICE);
21958c2ecf20Sopenharmony_ci	if (ret)
21968c2ecf20Sopenharmony_ci		return ret;
21978c2ecf20Sopenharmony_ci
21988c2ecf20Sopenharmony_ci	/* Save the workarea address since it is updated in order to perform
21998c2ecf20Sopenharmony_ci	 * the concatenation
22008c2ecf20Sopenharmony_ci	 */
22018c2ecf20Sopenharmony_ci	save = src.address;
22028c2ecf20Sopenharmony_ci
22038c2ecf20Sopenharmony_ci	/* Copy the ECC modulus */
22048c2ecf20Sopenharmony_ci	ret = ccp_reverse_set_dm_area(&src, 0, ecc->mod, 0, ecc->mod_len);
22058c2ecf20Sopenharmony_ci	if (ret)
22068c2ecf20Sopenharmony_ci		goto e_src;
22078c2ecf20Sopenharmony_ci	src.address += CCP_ECC_OPERAND_SIZE;
22088c2ecf20Sopenharmony_ci
22098c2ecf20Sopenharmony_ci	/* Copy the first operand */
22108c2ecf20Sopenharmony_ci	ret = ccp_reverse_set_dm_area(&src, 0, ecc->u.mm.operand_1, 0,
22118c2ecf20Sopenharmony_ci				      ecc->u.mm.operand_1_len);
22128c2ecf20Sopenharmony_ci	if (ret)
22138c2ecf20Sopenharmony_ci		goto e_src;
22148c2ecf20Sopenharmony_ci	src.address += CCP_ECC_OPERAND_SIZE;
22158c2ecf20Sopenharmony_ci
22168c2ecf20Sopenharmony_ci	if (ecc->function != CCP_ECC_FUNCTION_MINV_384BIT) {
22178c2ecf20Sopenharmony_ci		/* Copy the second operand */
22188c2ecf20Sopenharmony_ci		ret = ccp_reverse_set_dm_area(&src, 0, ecc->u.mm.operand_2, 0,
22198c2ecf20Sopenharmony_ci					      ecc->u.mm.operand_2_len);
22208c2ecf20Sopenharmony_ci		if (ret)
22218c2ecf20Sopenharmony_ci			goto e_src;
22228c2ecf20Sopenharmony_ci		src.address += CCP_ECC_OPERAND_SIZE;
22238c2ecf20Sopenharmony_ci	}
22248c2ecf20Sopenharmony_ci
22258c2ecf20Sopenharmony_ci	/* Restore the workarea address */
22268c2ecf20Sopenharmony_ci	src.address = save;
22278c2ecf20Sopenharmony_ci
22288c2ecf20Sopenharmony_ci	/* Prepare the output area for the operation */
22298c2ecf20Sopenharmony_ci	ret = ccp_init_dm_workarea(&dst, cmd_q, CCP_ECC_DST_BUF_SIZE,
22308c2ecf20Sopenharmony_ci				   DMA_FROM_DEVICE);
22318c2ecf20Sopenharmony_ci	if (ret)
22328c2ecf20Sopenharmony_ci		goto e_src;
22338c2ecf20Sopenharmony_ci
22348c2ecf20Sopenharmony_ci	op.soc = 1;
22358c2ecf20Sopenharmony_ci	op.src.u.dma.address = src.dma.address;
22368c2ecf20Sopenharmony_ci	op.src.u.dma.offset = 0;
22378c2ecf20Sopenharmony_ci	op.src.u.dma.length = src.length;
22388c2ecf20Sopenharmony_ci	op.dst.u.dma.address = dst.dma.address;
22398c2ecf20Sopenharmony_ci	op.dst.u.dma.offset = 0;
22408c2ecf20Sopenharmony_ci	op.dst.u.dma.length = dst.length;
22418c2ecf20Sopenharmony_ci
22428c2ecf20Sopenharmony_ci	op.u.ecc.function = cmd->u.ecc.function;
22438c2ecf20Sopenharmony_ci
22448c2ecf20Sopenharmony_ci	ret = cmd_q->ccp->vdata->perform->ecc(&op);
22458c2ecf20Sopenharmony_ci	if (ret) {
22468c2ecf20Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
22478c2ecf20Sopenharmony_ci		goto e_dst;
22488c2ecf20Sopenharmony_ci	}
22498c2ecf20Sopenharmony_ci
22508c2ecf20Sopenharmony_ci	ecc->ecc_result = le16_to_cpup(
22518c2ecf20Sopenharmony_ci		(const __le16 *)(dst.address + CCP_ECC_RESULT_OFFSET));
22528c2ecf20Sopenharmony_ci	if (!(ecc->ecc_result & CCP_ECC_RESULT_SUCCESS)) {
22538c2ecf20Sopenharmony_ci		ret = -EIO;
22548c2ecf20Sopenharmony_ci		goto e_dst;
22558c2ecf20Sopenharmony_ci	}
22568c2ecf20Sopenharmony_ci
22578c2ecf20Sopenharmony_ci	/* Save the ECC result */
22588c2ecf20Sopenharmony_ci	ccp_reverse_get_dm_area(&dst, 0, ecc->u.mm.result, 0,
22598c2ecf20Sopenharmony_ci				CCP_ECC_MODULUS_BYTES);
22608c2ecf20Sopenharmony_ci
22618c2ecf20Sopenharmony_cie_dst:
22628c2ecf20Sopenharmony_ci	ccp_dm_free(&dst);
22638c2ecf20Sopenharmony_ci
22648c2ecf20Sopenharmony_cie_src:
22658c2ecf20Sopenharmony_ci	ccp_dm_free(&src);
22668c2ecf20Sopenharmony_ci
22678c2ecf20Sopenharmony_ci	return ret;
22688c2ecf20Sopenharmony_ci}
22698c2ecf20Sopenharmony_ci
22708c2ecf20Sopenharmony_cistatic int ccp_run_ecc_pm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
22718c2ecf20Sopenharmony_ci{
22728c2ecf20Sopenharmony_ci	struct ccp_ecc_engine *ecc = &cmd->u.ecc;
22738c2ecf20Sopenharmony_ci	struct ccp_dm_workarea src, dst;
22748c2ecf20Sopenharmony_ci	struct ccp_op op;
22758c2ecf20Sopenharmony_ci	int ret;
22768c2ecf20Sopenharmony_ci	u8 *save;
22778c2ecf20Sopenharmony_ci
22788c2ecf20Sopenharmony_ci	if (!ecc->u.pm.point_1.x ||
22798c2ecf20Sopenharmony_ci	    (ecc->u.pm.point_1.x_len > CCP_ECC_MODULUS_BYTES) ||
22808c2ecf20Sopenharmony_ci	    !ecc->u.pm.point_1.y ||
22818c2ecf20Sopenharmony_ci	    (ecc->u.pm.point_1.y_len > CCP_ECC_MODULUS_BYTES))
22828c2ecf20Sopenharmony_ci		return -EINVAL;
22838c2ecf20Sopenharmony_ci
22848c2ecf20Sopenharmony_ci	if (ecc->function == CCP_ECC_FUNCTION_PADD_384BIT) {
22858c2ecf20Sopenharmony_ci		if (!ecc->u.pm.point_2.x ||
22868c2ecf20Sopenharmony_ci		    (ecc->u.pm.point_2.x_len > CCP_ECC_MODULUS_BYTES) ||
22878c2ecf20Sopenharmony_ci		    !ecc->u.pm.point_2.y ||
22888c2ecf20Sopenharmony_ci		    (ecc->u.pm.point_2.y_len > CCP_ECC_MODULUS_BYTES))
22898c2ecf20Sopenharmony_ci			return -EINVAL;
22908c2ecf20Sopenharmony_ci	} else {
22918c2ecf20Sopenharmony_ci		if (!ecc->u.pm.domain_a ||
22928c2ecf20Sopenharmony_ci		    (ecc->u.pm.domain_a_len > CCP_ECC_MODULUS_BYTES))
22938c2ecf20Sopenharmony_ci			return -EINVAL;
22948c2ecf20Sopenharmony_ci
22958c2ecf20Sopenharmony_ci		if (ecc->function == CCP_ECC_FUNCTION_PMUL_384BIT)
22968c2ecf20Sopenharmony_ci			if (!ecc->u.pm.scalar ||
22978c2ecf20Sopenharmony_ci			    (ecc->u.pm.scalar_len > CCP_ECC_MODULUS_BYTES))
22988c2ecf20Sopenharmony_ci				return -EINVAL;
22998c2ecf20Sopenharmony_ci	}
23008c2ecf20Sopenharmony_ci
23018c2ecf20Sopenharmony_ci	if (!ecc->u.pm.result.x ||
23028c2ecf20Sopenharmony_ci	    (ecc->u.pm.result.x_len < CCP_ECC_MODULUS_BYTES) ||
23038c2ecf20Sopenharmony_ci	    !ecc->u.pm.result.y ||
23048c2ecf20Sopenharmony_ci	    (ecc->u.pm.result.y_len < CCP_ECC_MODULUS_BYTES))
23058c2ecf20Sopenharmony_ci		return -EINVAL;
23068c2ecf20Sopenharmony_ci
23078c2ecf20Sopenharmony_ci	memset(&op, 0, sizeof(op));
23088c2ecf20Sopenharmony_ci	op.cmd_q = cmd_q;
23098c2ecf20Sopenharmony_ci	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
23108c2ecf20Sopenharmony_ci
23118c2ecf20Sopenharmony_ci	/* Concatenate the modulus and the operands. Both the modulus and
23128c2ecf20Sopenharmony_ci	 * the operands must be in little endian format.  Since the input
23138c2ecf20Sopenharmony_ci	 * is in big endian format it must be converted and placed in a
23148c2ecf20Sopenharmony_ci	 * fixed length buffer.
23158c2ecf20Sopenharmony_ci	 */
23168c2ecf20Sopenharmony_ci	ret = ccp_init_dm_workarea(&src, cmd_q, CCP_ECC_SRC_BUF_SIZE,
23178c2ecf20Sopenharmony_ci				   DMA_TO_DEVICE);
23188c2ecf20Sopenharmony_ci	if (ret)
23198c2ecf20Sopenharmony_ci		return ret;
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_ci	/* Save the workarea address since it is updated in order to perform
23228c2ecf20Sopenharmony_ci	 * the concatenation
23238c2ecf20Sopenharmony_ci	 */
23248c2ecf20Sopenharmony_ci	save = src.address;
23258c2ecf20Sopenharmony_ci
23268c2ecf20Sopenharmony_ci	/* Copy the ECC modulus */
23278c2ecf20Sopenharmony_ci	ret = ccp_reverse_set_dm_area(&src, 0, ecc->mod, 0, ecc->mod_len);
23288c2ecf20Sopenharmony_ci	if (ret)
23298c2ecf20Sopenharmony_ci		goto e_src;
23308c2ecf20Sopenharmony_ci	src.address += CCP_ECC_OPERAND_SIZE;
23318c2ecf20Sopenharmony_ci
23328c2ecf20Sopenharmony_ci	/* Copy the first point X and Y coordinate */
23338c2ecf20Sopenharmony_ci	ret = ccp_reverse_set_dm_area(&src, 0, ecc->u.pm.point_1.x, 0,
23348c2ecf20Sopenharmony_ci				      ecc->u.pm.point_1.x_len);
23358c2ecf20Sopenharmony_ci	if (ret)
23368c2ecf20Sopenharmony_ci		goto e_src;
23378c2ecf20Sopenharmony_ci	src.address += CCP_ECC_OPERAND_SIZE;
23388c2ecf20Sopenharmony_ci	ret = ccp_reverse_set_dm_area(&src, 0, ecc->u.pm.point_1.y, 0,
23398c2ecf20Sopenharmony_ci				      ecc->u.pm.point_1.y_len);
23408c2ecf20Sopenharmony_ci	if (ret)
23418c2ecf20Sopenharmony_ci		goto e_src;
23428c2ecf20Sopenharmony_ci	src.address += CCP_ECC_OPERAND_SIZE;
23438c2ecf20Sopenharmony_ci
23448c2ecf20Sopenharmony_ci	/* Set the first point Z coordinate to 1 */
23458c2ecf20Sopenharmony_ci	*src.address = 0x01;
23468c2ecf20Sopenharmony_ci	src.address += CCP_ECC_OPERAND_SIZE;
23478c2ecf20Sopenharmony_ci
23488c2ecf20Sopenharmony_ci	if (ecc->function == CCP_ECC_FUNCTION_PADD_384BIT) {
23498c2ecf20Sopenharmony_ci		/* Copy the second point X and Y coordinate */
23508c2ecf20Sopenharmony_ci		ret = ccp_reverse_set_dm_area(&src, 0, ecc->u.pm.point_2.x, 0,
23518c2ecf20Sopenharmony_ci					      ecc->u.pm.point_2.x_len);
23528c2ecf20Sopenharmony_ci		if (ret)
23538c2ecf20Sopenharmony_ci			goto e_src;
23548c2ecf20Sopenharmony_ci		src.address += CCP_ECC_OPERAND_SIZE;
23558c2ecf20Sopenharmony_ci		ret = ccp_reverse_set_dm_area(&src, 0, ecc->u.pm.point_2.y, 0,
23568c2ecf20Sopenharmony_ci					      ecc->u.pm.point_2.y_len);
23578c2ecf20Sopenharmony_ci		if (ret)
23588c2ecf20Sopenharmony_ci			goto e_src;
23598c2ecf20Sopenharmony_ci		src.address += CCP_ECC_OPERAND_SIZE;
23608c2ecf20Sopenharmony_ci
23618c2ecf20Sopenharmony_ci		/* Set the second point Z coordinate to 1 */
23628c2ecf20Sopenharmony_ci		*src.address = 0x01;
23638c2ecf20Sopenharmony_ci		src.address += CCP_ECC_OPERAND_SIZE;
23648c2ecf20Sopenharmony_ci	} else {
23658c2ecf20Sopenharmony_ci		/* Copy the Domain "a" parameter */
23668c2ecf20Sopenharmony_ci		ret = ccp_reverse_set_dm_area(&src, 0, ecc->u.pm.domain_a, 0,
23678c2ecf20Sopenharmony_ci					      ecc->u.pm.domain_a_len);
23688c2ecf20Sopenharmony_ci		if (ret)
23698c2ecf20Sopenharmony_ci			goto e_src;
23708c2ecf20Sopenharmony_ci		src.address += CCP_ECC_OPERAND_SIZE;
23718c2ecf20Sopenharmony_ci
23728c2ecf20Sopenharmony_ci		if (ecc->function == CCP_ECC_FUNCTION_PMUL_384BIT) {
23738c2ecf20Sopenharmony_ci			/* Copy the scalar value */
23748c2ecf20Sopenharmony_ci			ret = ccp_reverse_set_dm_area(&src, 0,
23758c2ecf20Sopenharmony_ci						      ecc->u.pm.scalar, 0,
23768c2ecf20Sopenharmony_ci						      ecc->u.pm.scalar_len);
23778c2ecf20Sopenharmony_ci			if (ret)
23788c2ecf20Sopenharmony_ci				goto e_src;
23798c2ecf20Sopenharmony_ci			src.address += CCP_ECC_OPERAND_SIZE;
23808c2ecf20Sopenharmony_ci		}
23818c2ecf20Sopenharmony_ci	}
23828c2ecf20Sopenharmony_ci
23838c2ecf20Sopenharmony_ci	/* Restore the workarea address */
23848c2ecf20Sopenharmony_ci	src.address = save;
23858c2ecf20Sopenharmony_ci
23868c2ecf20Sopenharmony_ci	/* Prepare the output area for the operation */
23878c2ecf20Sopenharmony_ci	ret = ccp_init_dm_workarea(&dst, cmd_q, CCP_ECC_DST_BUF_SIZE,
23888c2ecf20Sopenharmony_ci				   DMA_FROM_DEVICE);
23898c2ecf20Sopenharmony_ci	if (ret)
23908c2ecf20Sopenharmony_ci		goto e_src;
23918c2ecf20Sopenharmony_ci
23928c2ecf20Sopenharmony_ci	op.soc = 1;
23938c2ecf20Sopenharmony_ci	op.src.u.dma.address = src.dma.address;
23948c2ecf20Sopenharmony_ci	op.src.u.dma.offset = 0;
23958c2ecf20Sopenharmony_ci	op.src.u.dma.length = src.length;
23968c2ecf20Sopenharmony_ci	op.dst.u.dma.address = dst.dma.address;
23978c2ecf20Sopenharmony_ci	op.dst.u.dma.offset = 0;
23988c2ecf20Sopenharmony_ci	op.dst.u.dma.length = dst.length;
23998c2ecf20Sopenharmony_ci
24008c2ecf20Sopenharmony_ci	op.u.ecc.function = cmd->u.ecc.function;
24018c2ecf20Sopenharmony_ci
24028c2ecf20Sopenharmony_ci	ret = cmd_q->ccp->vdata->perform->ecc(&op);
24038c2ecf20Sopenharmony_ci	if (ret) {
24048c2ecf20Sopenharmony_ci		cmd->engine_error = cmd_q->cmd_error;
24058c2ecf20Sopenharmony_ci		goto e_dst;
24068c2ecf20Sopenharmony_ci	}
24078c2ecf20Sopenharmony_ci
24088c2ecf20Sopenharmony_ci	ecc->ecc_result = le16_to_cpup(
24098c2ecf20Sopenharmony_ci		(const __le16 *)(dst.address + CCP_ECC_RESULT_OFFSET));
24108c2ecf20Sopenharmony_ci	if (!(ecc->ecc_result & CCP_ECC_RESULT_SUCCESS)) {
24118c2ecf20Sopenharmony_ci		ret = -EIO;
24128c2ecf20Sopenharmony_ci		goto e_dst;
24138c2ecf20Sopenharmony_ci	}
24148c2ecf20Sopenharmony_ci
24158c2ecf20Sopenharmony_ci	/* Save the workarea address since it is updated as we walk through
24168c2ecf20Sopenharmony_ci	 * to copy the point math result
24178c2ecf20Sopenharmony_ci	 */
24188c2ecf20Sopenharmony_ci	save = dst.address;
24198c2ecf20Sopenharmony_ci
24208c2ecf20Sopenharmony_ci	/* Save the ECC result X and Y coordinates */
24218c2ecf20Sopenharmony_ci	ccp_reverse_get_dm_area(&dst, 0, ecc->u.pm.result.x, 0,
24228c2ecf20Sopenharmony_ci				CCP_ECC_MODULUS_BYTES);
24238c2ecf20Sopenharmony_ci	dst.address += CCP_ECC_OUTPUT_SIZE;
24248c2ecf20Sopenharmony_ci	ccp_reverse_get_dm_area(&dst, 0, ecc->u.pm.result.y, 0,
24258c2ecf20Sopenharmony_ci				CCP_ECC_MODULUS_BYTES);
24268c2ecf20Sopenharmony_ci	dst.address += CCP_ECC_OUTPUT_SIZE;
24278c2ecf20Sopenharmony_ci
24288c2ecf20Sopenharmony_ci	/* Restore the workarea address */
24298c2ecf20Sopenharmony_ci	dst.address = save;
24308c2ecf20Sopenharmony_ci
24318c2ecf20Sopenharmony_cie_dst:
24328c2ecf20Sopenharmony_ci	ccp_dm_free(&dst);
24338c2ecf20Sopenharmony_ci
24348c2ecf20Sopenharmony_cie_src:
24358c2ecf20Sopenharmony_ci	ccp_dm_free(&src);
24368c2ecf20Sopenharmony_ci
24378c2ecf20Sopenharmony_ci	return ret;
24388c2ecf20Sopenharmony_ci}
24398c2ecf20Sopenharmony_ci
24408c2ecf20Sopenharmony_cistatic noinline_for_stack int
24418c2ecf20Sopenharmony_ciccp_run_ecc_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
24428c2ecf20Sopenharmony_ci{
24438c2ecf20Sopenharmony_ci	struct ccp_ecc_engine *ecc = &cmd->u.ecc;
24448c2ecf20Sopenharmony_ci
24458c2ecf20Sopenharmony_ci	ecc->ecc_result = 0;
24468c2ecf20Sopenharmony_ci
24478c2ecf20Sopenharmony_ci	if (!ecc->mod ||
24488c2ecf20Sopenharmony_ci	    (ecc->mod_len > CCP_ECC_MODULUS_BYTES))
24498c2ecf20Sopenharmony_ci		return -EINVAL;
24508c2ecf20Sopenharmony_ci
24518c2ecf20Sopenharmony_ci	switch (ecc->function) {
24528c2ecf20Sopenharmony_ci	case CCP_ECC_FUNCTION_MMUL_384BIT:
24538c2ecf20Sopenharmony_ci	case CCP_ECC_FUNCTION_MADD_384BIT:
24548c2ecf20Sopenharmony_ci	case CCP_ECC_FUNCTION_MINV_384BIT:
24558c2ecf20Sopenharmony_ci		return ccp_run_ecc_mm_cmd(cmd_q, cmd);
24568c2ecf20Sopenharmony_ci
24578c2ecf20Sopenharmony_ci	case CCP_ECC_FUNCTION_PADD_384BIT:
24588c2ecf20Sopenharmony_ci	case CCP_ECC_FUNCTION_PMUL_384BIT:
24598c2ecf20Sopenharmony_ci	case CCP_ECC_FUNCTION_PDBL_384BIT:
24608c2ecf20Sopenharmony_ci		return ccp_run_ecc_pm_cmd(cmd_q, cmd);
24618c2ecf20Sopenharmony_ci
24628c2ecf20Sopenharmony_ci	default:
24638c2ecf20Sopenharmony_ci		return -EINVAL;
24648c2ecf20Sopenharmony_ci	}
24658c2ecf20Sopenharmony_ci}
24668c2ecf20Sopenharmony_ci
24678c2ecf20Sopenharmony_ciint ccp_run_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
24688c2ecf20Sopenharmony_ci{
24698c2ecf20Sopenharmony_ci	int ret;
24708c2ecf20Sopenharmony_ci
24718c2ecf20Sopenharmony_ci	cmd->engine_error = 0;
24728c2ecf20Sopenharmony_ci	cmd_q->cmd_error = 0;
24738c2ecf20Sopenharmony_ci	cmd_q->int_rcvd = 0;
24748c2ecf20Sopenharmony_ci	cmd_q->free_slots = cmd_q->ccp->vdata->perform->get_free_slots(cmd_q);
24758c2ecf20Sopenharmony_ci
24768c2ecf20Sopenharmony_ci	switch (cmd->engine) {
24778c2ecf20Sopenharmony_ci	case CCP_ENGINE_AES:
24788c2ecf20Sopenharmony_ci		switch (cmd->u.aes.mode) {
24798c2ecf20Sopenharmony_ci		case CCP_AES_MODE_CMAC:
24808c2ecf20Sopenharmony_ci			ret = ccp_run_aes_cmac_cmd(cmd_q, cmd);
24818c2ecf20Sopenharmony_ci			break;
24828c2ecf20Sopenharmony_ci		case CCP_AES_MODE_GCM:
24838c2ecf20Sopenharmony_ci			ret = ccp_run_aes_gcm_cmd(cmd_q, cmd);
24848c2ecf20Sopenharmony_ci			break;
24858c2ecf20Sopenharmony_ci		default:
24868c2ecf20Sopenharmony_ci			ret = ccp_run_aes_cmd(cmd_q, cmd);
24878c2ecf20Sopenharmony_ci			break;
24888c2ecf20Sopenharmony_ci		}
24898c2ecf20Sopenharmony_ci		break;
24908c2ecf20Sopenharmony_ci	case CCP_ENGINE_XTS_AES_128:
24918c2ecf20Sopenharmony_ci		ret = ccp_run_xts_aes_cmd(cmd_q, cmd);
24928c2ecf20Sopenharmony_ci		break;
24938c2ecf20Sopenharmony_ci	case CCP_ENGINE_DES3:
24948c2ecf20Sopenharmony_ci		ret = ccp_run_des3_cmd(cmd_q, cmd);
24958c2ecf20Sopenharmony_ci		break;
24968c2ecf20Sopenharmony_ci	case CCP_ENGINE_SHA:
24978c2ecf20Sopenharmony_ci		ret = ccp_run_sha_cmd(cmd_q, cmd);
24988c2ecf20Sopenharmony_ci		break;
24998c2ecf20Sopenharmony_ci	case CCP_ENGINE_RSA:
25008c2ecf20Sopenharmony_ci		ret = ccp_run_rsa_cmd(cmd_q, cmd);
25018c2ecf20Sopenharmony_ci		break;
25028c2ecf20Sopenharmony_ci	case CCP_ENGINE_PASSTHRU:
25038c2ecf20Sopenharmony_ci		if (cmd->flags & CCP_CMD_PASSTHRU_NO_DMA_MAP)
25048c2ecf20Sopenharmony_ci			ret = ccp_run_passthru_nomap_cmd(cmd_q, cmd);
25058c2ecf20Sopenharmony_ci		else
25068c2ecf20Sopenharmony_ci			ret = ccp_run_passthru_cmd(cmd_q, cmd);
25078c2ecf20Sopenharmony_ci		break;
25088c2ecf20Sopenharmony_ci	case CCP_ENGINE_ECC:
25098c2ecf20Sopenharmony_ci		ret = ccp_run_ecc_cmd(cmd_q, cmd);
25108c2ecf20Sopenharmony_ci		break;
25118c2ecf20Sopenharmony_ci	default:
25128c2ecf20Sopenharmony_ci		ret = -EINVAL;
25138c2ecf20Sopenharmony_ci	}
25148c2ecf20Sopenharmony_ci
25158c2ecf20Sopenharmony_ci	return ret;
25168c2ecf20Sopenharmony_ci}
2517