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