162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * caam - Freescale FSL CAAM support for ahash functions of crypto API 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2011 Freescale Semiconductor, Inc. 662306a36Sopenharmony_ci * Copyright 2018-2019, 2023 NXP 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Based on caamalg.c crypto API driver. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * relationship of digest job descriptor or first job descriptor after init to 1162306a36Sopenharmony_ci * shared descriptors: 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * --------------- --------------- 1462306a36Sopenharmony_ci * | JobDesc #1 |-------------------->| ShareDesc | 1562306a36Sopenharmony_ci * | *(packet 1) | | (hashKey) | 1662306a36Sopenharmony_ci * --------------- | (operation) | 1762306a36Sopenharmony_ci * --------------- 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * relationship of subsequent job descriptors to shared descriptors: 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * --------------- --------------- 2262306a36Sopenharmony_ci * | JobDesc #2 |-------------------->| ShareDesc | 2362306a36Sopenharmony_ci * | *(packet 2) | |------------->| (hashKey) | 2462306a36Sopenharmony_ci * --------------- | |-------->| (operation) | 2562306a36Sopenharmony_ci * . | | | (load ctx2) | 2662306a36Sopenharmony_ci * . | | --------------- 2762306a36Sopenharmony_ci * --------------- | | 2862306a36Sopenharmony_ci * | JobDesc #3 |------| | 2962306a36Sopenharmony_ci * | *(packet 3) | | 3062306a36Sopenharmony_ci * --------------- | 3162306a36Sopenharmony_ci * . | 3262306a36Sopenharmony_ci * . | 3362306a36Sopenharmony_ci * --------------- | 3462306a36Sopenharmony_ci * | JobDesc #4 |------------ 3562306a36Sopenharmony_ci * | *(packet 4) | 3662306a36Sopenharmony_ci * --------------- 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * The SharedDesc never changes for a connection unless rekeyed, but 3962306a36Sopenharmony_ci * each packet will likely be in a different place. So all we need 4062306a36Sopenharmony_ci * to know to process the packet is where the input is, where the 4162306a36Sopenharmony_ci * output goes, and what context we want to process with. Context is 4262306a36Sopenharmony_ci * in the SharedDesc, packet references in the JobDesc. 4362306a36Sopenharmony_ci * 4462306a36Sopenharmony_ci * So, a job desc looks like: 4562306a36Sopenharmony_ci * 4662306a36Sopenharmony_ci * --------------------- 4762306a36Sopenharmony_ci * | Header | 4862306a36Sopenharmony_ci * | ShareDesc Pointer | 4962306a36Sopenharmony_ci * | SEQ_OUT_PTR | 5062306a36Sopenharmony_ci * | (output buffer) | 5162306a36Sopenharmony_ci * | (output length) | 5262306a36Sopenharmony_ci * | SEQ_IN_PTR | 5362306a36Sopenharmony_ci * | (input buffer) | 5462306a36Sopenharmony_ci * | (input length) | 5562306a36Sopenharmony_ci * --------------------- 5662306a36Sopenharmony_ci */ 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#include "compat.h" 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#include "regs.h" 6162306a36Sopenharmony_ci#include "intern.h" 6262306a36Sopenharmony_ci#include "desc_constr.h" 6362306a36Sopenharmony_ci#include "jr.h" 6462306a36Sopenharmony_ci#include "error.h" 6562306a36Sopenharmony_ci#include "sg_sw_sec4.h" 6662306a36Sopenharmony_ci#include "key_gen.h" 6762306a36Sopenharmony_ci#include "caamhash_desc.h" 6862306a36Sopenharmony_ci#include <crypto/internal/engine.h> 6962306a36Sopenharmony_ci#include <crypto/internal/hash.h> 7062306a36Sopenharmony_ci#include <linux/dma-mapping.h> 7162306a36Sopenharmony_ci#include <linux/err.h> 7262306a36Sopenharmony_ci#include <linux/kernel.h> 7362306a36Sopenharmony_ci#include <linux/slab.h> 7462306a36Sopenharmony_ci#include <linux/string.h> 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#define CAAM_CRA_PRIORITY 3000 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/* max hash key is max split key size */ 7962306a36Sopenharmony_ci#define CAAM_MAX_HASH_KEY_SIZE (SHA512_DIGEST_SIZE * 2) 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci#define CAAM_MAX_HASH_BLOCK_SIZE SHA512_BLOCK_SIZE 8262306a36Sopenharmony_ci#define CAAM_MAX_HASH_DIGEST_SIZE SHA512_DIGEST_SIZE 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci#define DESC_HASH_MAX_USED_BYTES (DESC_AHASH_FINAL_LEN + \ 8562306a36Sopenharmony_ci CAAM_MAX_HASH_KEY_SIZE) 8662306a36Sopenharmony_ci#define DESC_HASH_MAX_USED_LEN (DESC_HASH_MAX_USED_BYTES / CAAM_CMD_SZ) 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci/* caam context sizes for hashes: running digest + 8 */ 8962306a36Sopenharmony_ci#define HASH_MSG_LEN 8 9062306a36Sopenharmony_ci#define MAX_CTX_LEN (HASH_MSG_LEN + SHA512_DIGEST_SIZE) 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic struct list_head hash_list; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci/* ahash per-session context */ 9562306a36Sopenharmony_cistruct caam_hash_ctx { 9662306a36Sopenharmony_ci u32 sh_desc_update[DESC_HASH_MAX_USED_LEN] ____cacheline_aligned; 9762306a36Sopenharmony_ci u32 sh_desc_update_first[DESC_HASH_MAX_USED_LEN] ____cacheline_aligned; 9862306a36Sopenharmony_ci u32 sh_desc_fin[DESC_HASH_MAX_USED_LEN] ____cacheline_aligned; 9962306a36Sopenharmony_ci u32 sh_desc_digest[DESC_HASH_MAX_USED_LEN] ____cacheline_aligned; 10062306a36Sopenharmony_ci u8 key[CAAM_MAX_HASH_KEY_SIZE] ____cacheline_aligned; 10162306a36Sopenharmony_ci dma_addr_t sh_desc_update_dma ____cacheline_aligned; 10262306a36Sopenharmony_ci dma_addr_t sh_desc_update_first_dma; 10362306a36Sopenharmony_ci dma_addr_t sh_desc_fin_dma; 10462306a36Sopenharmony_ci dma_addr_t sh_desc_digest_dma; 10562306a36Sopenharmony_ci enum dma_data_direction dir; 10662306a36Sopenharmony_ci enum dma_data_direction key_dir; 10762306a36Sopenharmony_ci struct device *jrdev; 10862306a36Sopenharmony_ci int ctx_len; 10962306a36Sopenharmony_ci struct alginfo adata; 11062306a36Sopenharmony_ci}; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci/* ahash state */ 11362306a36Sopenharmony_cistruct caam_hash_state { 11462306a36Sopenharmony_ci dma_addr_t buf_dma; 11562306a36Sopenharmony_ci dma_addr_t ctx_dma; 11662306a36Sopenharmony_ci int ctx_dma_len; 11762306a36Sopenharmony_ci u8 buf[CAAM_MAX_HASH_BLOCK_SIZE] ____cacheline_aligned; 11862306a36Sopenharmony_ci int buflen; 11962306a36Sopenharmony_ci int next_buflen; 12062306a36Sopenharmony_ci u8 caam_ctx[MAX_CTX_LEN] ____cacheline_aligned; 12162306a36Sopenharmony_ci int (*update)(struct ahash_request *req) ____cacheline_aligned; 12262306a36Sopenharmony_ci int (*final)(struct ahash_request *req); 12362306a36Sopenharmony_ci int (*finup)(struct ahash_request *req); 12462306a36Sopenharmony_ci struct ahash_edesc *edesc; 12562306a36Sopenharmony_ci void (*ahash_op_done)(struct device *jrdev, u32 *desc, u32 err, 12662306a36Sopenharmony_ci void *context); 12762306a36Sopenharmony_ci}; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistruct caam_export_state { 13062306a36Sopenharmony_ci u8 buf[CAAM_MAX_HASH_BLOCK_SIZE]; 13162306a36Sopenharmony_ci u8 caam_ctx[MAX_CTX_LEN]; 13262306a36Sopenharmony_ci int buflen; 13362306a36Sopenharmony_ci int (*update)(struct ahash_request *req); 13462306a36Sopenharmony_ci int (*final)(struct ahash_request *req); 13562306a36Sopenharmony_ci int (*finup)(struct ahash_request *req); 13662306a36Sopenharmony_ci}; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic inline bool is_cmac_aes(u32 algtype) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci return (algtype & (OP_ALG_ALGSEL_MASK | OP_ALG_AAI_MASK)) == 14162306a36Sopenharmony_ci (OP_ALG_ALGSEL_AES | OP_ALG_AAI_CMAC); 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci/* Common job descriptor seq in/out ptr routines */ 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/* Map state->caam_ctx, and append seq_out_ptr command that points to it */ 14662306a36Sopenharmony_cistatic inline int map_seq_out_ptr_ctx(u32 *desc, struct device *jrdev, 14762306a36Sopenharmony_ci struct caam_hash_state *state, 14862306a36Sopenharmony_ci int ctx_len) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci state->ctx_dma_len = ctx_len; 15162306a36Sopenharmony_ci state->ctx_dma = dma_map_single(jrdev, state->caam_ctx, 15262306a36Sopenharmony_ci ctx_len, DMA_FROM_DEVICE); 15362306a36Sopenharmony_ci if (dma_mapping_error(jrdev, state->ctx_dma)) { 15462306a36Sopenharmony_ci dev_err(jrdev, "unable to map ctx\n"); 15562306a36Sopenharmony_ci state->ctx_dma = 0; 15662306a36Sopenharmony_ci return -ENOMEM; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci append_seq_out_ptr(desc, state->ctx_dma, ctx_len, 0); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci return 0; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci/* Map current buffer in state (if length > 0) and put it in link table */ 16562306a36Sopenharmony_cistatic inline int buf_map_to_sec4_sg(struct device *jrdev, 16662306a36Sopenharmony_ci struct sec4_sg_entry *sec4_sg, 16762306a36Sopenharmony_ci struct caam_hash_state *state) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci int buflen = state->buflen; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci if (!buflen) 17262306a36Sopenharmony_ci return 0; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci state->buf_dma = dma_map_single(jrdev, state->buf, buflen, 17562306a36Sopenharmony_ci DMA_TO_DEVICE); 17662306a36Sopenharmony_ci if (dma_mapping_error(jrdev, state->buf_dma)) { 17762306a36Sopenharmony_ci dev_err(jrdev, "unable to map buf\n"); 17862306a36Sopenharmony_ci state->buf_dma = 0; 17962306a36Sopenharmony_ci return -ENOMEM; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci dma_to_sec4_sg_one(sec4_sg, state->buf_dma, buflen, 0); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci return 0; 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci/* Map state->caam_ctx, and add it to link table */ 18862306a36Sopenharmony_cistatic inline int ctx_map_to_sec4_sg(struct device *jrdev, 18962306a36Sopenharmony_ci struct caam_hash_state *state, int ctx_len, 19062306a36Sopenharmony_ci struct sec4_sg_entry *sec4_sg, u32 flag) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci state->ctx_dma_len = ctx_len; 19362306a36Sopenharmony_ci state->ctx_dma = dma_map_single(jrdev, state->caam_ctx, ctx_len, flag); 19462306a36Sopenharmony_ci if (dma_mapping_error(jrdev, state->ctx_dma)) { 19562306a36Sopenharmony_ci dev_err(jrdev, "unable to map ctx\n"); 19662306a36Sopenharmony_ci state->ctx_dma = 0; 19762306a36Sopenharmony_ci return -ENOMEM; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci dma_to_sec4_sg_one(sec4_sg, state->ctx_dma, ctx_len, 0); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci return 0; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic int ahash_set_sh_desc(struct crypto_ahash *ahash) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci struct caam_hash_ctx *ctx = crypto_ahash_ctx_dma(ahash); 20862306a36Sopenharmony_ci int digestsize = crypto_ahash_digestsize(ahash); 20962306a36Sopenharmony_ci struct device *jrdev = ctx->jrdev; 21062306a36Sopenharmony_ci struct caam_drv_private *ctrlpriv = dev_get_drvdata(jrdev->parent); 21162306a36Sopenharmony_ci u32 *desc; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci ctx->adata.key_virt = ctx->key; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci /* ahash_update shared descriptor */ 21662306a36Sopenharmony_ci desc = ctx->sh_desc_update; 21762306a36Sopenharmony_ci cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_UPDATE, ctx->ctx_len, 21862306a36Sopenharmony_ci ctx->ctx_len, true, ctrlpriv->era); 21962306a36Sopenharmony_ci dma_sync_single_for_device(jrdev, ctx->sh_desc_update_dma, 22062306a36Sopenharmony_ci desc_bytes(desc), ctx->dir); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci print_hex_dump_debug("ahash update shdesc@"__stringify(__LINE__)": ", 22362306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 22462306a36Sopenharmony_ci 1); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* ahash_update_first shared descriptor */ 22762306a36Sopenharmony_ci desc = ctx->sh_desc_update_first; 22862306a36Sopenharmony_ci cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_INIT, ctx->ctx_len, 22962306a36Sopenharmony_ci ctx->ctx_len, false, ctrlpriv->era); 23062306a36Sopenharmony_ci dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma, 23162306a36Sopenharmony_ci desc_bytes(desc), ctx->dir); 23262306a36Sopenharmony_ci print_hex_dump_debug("ahash update first shdesc@"__stringify(__LINE__) 23362306a36Sopenharmony_ci ": ", DUMP_PREFIX_ADDRESS, 16, 4, desc, 23462306a36Sopenharmony_ci desc_bytes(desc), 1); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci /* ahash_final shared descriptor */ 23762306a36Sopenharmony_ci desc = ctx->sh_desc_fin; 23862306a36Sopenharmony_ci cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_FINALIZE, digestsize, 23962306a36Sopenharmony_ci ctx->ctx_len, true, ctrlpriv->era); 24062306a36Sopenharmony_ci dma_sync_single_for_device(jrdev, ctx->sh_desc_fin_dma, 24162306a36Sopenharmony_ci desc_bytes(desc), ctx->dir); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci print_hex_dump_debug("ahash final shdesc@"__stringify(__LINE__)": ", 24462306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, desc, 24562306a36Sopenharmony_ci desc_bytes(desc), 1); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* ahash_digest shared descriptor */ 24862306a36Sopenharmony_ci desc = ctx->sh_desc_digest; 24962306a36Sopenharmony_ci cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_INITFINAL, digestsize, 25062306a36Sopenharmony_ci ctx->ctx_len, false, ctrlpriv->era); 25162306a36Sopenharmony_ci dma_sync_single_for_device(jrdev, ctx->sh_desc_digest_dma, 25262306a36Sopenharmony_ci desc_bytes(desc), ctx->dir); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci print_hex_dump_debug("ahash digest shdesc@"__stringify(__LINE__)": ", 25562306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, desc, 25662306a36Sopenharmony_ci desc_bytes(desc), 1); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci return 0; 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cistatic int axcbc_set_sh_desc(struct crypto_ahash *ahash) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci struct caam_hash_ctx *ctx = crypto_ahash_ctx_dma(ahash); 26462306a36Sopenharmony_ci int digestsize = crypto_ahash_digestsize(ahash); 26562306a36Sopenharmony_ci struct device *jrdev = ctx->jrdev; 26662306a36Sopenharmony_ci u32 *desc; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci /* shared descriptor for ahash_update */ 26962306a36Sopenharmony_ci desc = ctx->sh_desc_update; 27062306a36Sopenharmony_ci cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_UPDATE, 27162306a36Sopenharmony_ci ctx->ctx_len, ctx->ctx_len); 27262306a36Sopenharmony_ci dma_sync_single_for_device(jrdev, ctx->sh_desc_update_dma, 27362306a36Sopenharmony_ci desc_bytes(desc), ctx->dir); 27462306a36Sopenharmony_ci print_hex_dump_debug("axcbc update shdesc@" __stringify(__LINE__)" : ", 27562306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 27662306a36Sopenharmony_ci 1); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci /* shared descriptor for ahash_{final,finup} */ 27962306a36Sopenharmony_ci desc = ctx->sh_desc_fin; 28062306a36Sopenharmony_ci cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_FINALIZE, 28162306a36Sopenharmony_ci digestsize, ctx->ctx_len); 28262306a36Sopenharmony_ci dma_sync_single_for_device(jrdev, ctx->sh_desc_fin_dma, 28362306a36Sopenharmony_ci desc_bytes(desc), ctx->dir); 28462306a36Sopenharmony_ci print_hex_dump_debug("axcbc finup shdesc@" __stringify(__LINE__)" : ", 28562306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 28662306a36Sopenharmony_ci 1); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci /* key is immediate data for INIT and INITFINAL states */ 28962306a36Sopenharmony_ci ctx->adata.key_virt = ctx->key; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci /* shared descriptor for first invocation of ahash_update */ 29262306a36Sopenharmony_ci desc = ctx->sh_desc_update_first; 29362306a36Sopenharmony_ci cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_INIT, ctx->ctx_len, 29462306a36Sopenharmony_ci ctx->ctx_len); 29562306a36Sopenharmony_ci dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma, 29662306a36Sopenharmony_ci desc_bytes(desc), ctx->dir); 29762306a36Sopenharmony_ci print_hex_dump_debug("axcbc update first shdesc@" __stringify(__LINE__) 29862306a36Sopenharmony_ci " : ", DUMP_PREFIX_ADDRESS, 16, 4, desc, 29962306a36Sopenharmony_ci desc_bytes(desc), 1); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* shared descriptor for ahash_digest */ 30262306a36Sopenharmony_ci desc = ctx->sh_desc_digest; 30362306a36Sopenharmony_ci cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_INITFINAL, 30462306a36Sopenharmony_ci digestsize, ctx->ctx_len); 30562306a36Sopenharmony_ci dma_sync_single_for_device(jrdev, ctx->sh_desc_digest_dma, 30662306a36Sopenharmony_ci desc_bytes(desc), ctx->dir); 30762306a36Sopenharmony_ci print_hex_dump_debug("axcbc digest shdesc@" __stringify(__LINE__)" : ", 30862306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 30962306a36Sopenharmony_ci 1); 31062306a36Sopenharmony_ci return 0; 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic int acmac_set_sh_desc(struct crypto_ahash *ahash) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci struct caam_hash_ctx *ctx = crypto_ahash_ctx_dma(ahash); 31662306a36Sopenharmony_ci int digestsize = crypto_ahash_digestsize(ahash); 31762306a36Sopenharmony_ci struct device *jrdev = ctx->jrdev; 31862306a36Sopenharmony_ci u32 *desc; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci /* shared descriptor for ahash_update */ 32162306a36Sopenharmony_ci desc = ctx->sh_desc_update; 32262306a36Sopenharmony_ci cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_UPDATE, 32362306a36Sopenharmony_ci ctx->ctx_len, ctx->ctx_len); 32462306a36Sopenharmony_ci dma_sync_single_for_device(jrdev, ctx->sh_desc_update_dma, 32562306a36Sopenharmony_ci desc_bytes(desc), ctx->dir); 32662306a36Sopenharmony_ci print_hex_dump_debug("acmac update shdesc@" __stringify(__LINE__)" : ", 32762306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, desc, 32862306a36Sopenharmony_ci desc_bytes(desc), 1); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci /* shared descriptor for ahash_{final,finup} */ 33162306a36Sopenharmony_ci desc = ctx->sh_desc_fin; 33262306a36Sopenharmony_ci cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_FINALIZE, 33362306a36Sopenharmony_ci digestsize, ctx->ctx_len); 33462306a36Sopenharmony_ci dma_sync_single_for_device(jrdev, ctx->sh_desc_fin_dma, 33562306a36Sopenharmony_ci desc_bytes(desc), ctx->dir); 33662306a36Sopenharmony_ci print_hex_dump_debug("acmac finup shdesc@" __stringify(__LINE__)" : ", 33762306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, desc, 33862306a36Sopenharmony_ci desc_bytes(desc), 1); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci /* shared descriptor for first invocation of ahash_update */ 34162306a36Sopenharmony_ci desc = ctx->sh_desc_update_first; 34262306a36Sopenharmony_ci cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_INIT, ctx->ctx_len, 34362306a36Sopenharmony_ci ctx->ctx_len); 34462306a36Sopenharmony_ci dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma, 34562306a36Sopenharmony_ci desc_bytes(desc), ctx->dir); 34662306a36Sopenharmony_ci print_hex_dump_debug("acmac update first shdesc@" __stringify(__LINE__) 34762306a36Sopenharmony_ci " : ", DUMP_PREFIX_ADDRESS, 16, 4, desc, 34862306a36Sopenharmony_ci desc_bytes(desc), 1); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci /* shared descriptor for ahash_digest */ 35162306a36Sopenharmony_ci desc = ctx->sh_desc_digest; 35262306a36Sopenharmony_ci cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_INITFINAL, 35362306a36Sopenharmony_ci digestsize, ctx->ctx_len); 35462306a36Sopenharmony_ci dma_sync_single_for_device(jrdev, ctx->sh_desc_digest_dma, 35562306a36Sopenharmony_ci desc_bytes(desc), ctx->dir); 35662306a36Sopenharmony_ci print_hex_dump_debug("acmac digest shdesc@" __stringify(__LINE__)" : ", 35762306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, desc, 35862306a36Sopenharmony_ci desc_bytes(desc), 1); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci return 0; 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci/* Digest hash size if it is too large */ 36462306a36Sopenharmony_cistatic int hash_digest_key(struct caam_hash_ctx *ctx, u32 *keylen, u8 *key, 36562306a36Sopenharmony_ci u32 digestsize) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci struct device *jrdev = ctx->jrdev; 36862306a36Sopenharmony_ci u32 *desc; 36962306a36Sopenharmony_ci struct split_key_result result; 37062306a36Sopenharmony_ci dma_addr_t key_dma; 37162306a36Sopenharmony_ci int ret; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci desc = kmalloc(CAAM_CMD_SZ * 8 + CAAM_PTR_SZ * 2, GFP_KERNEL); 37462306a36Sopenharmony_ci if (!desc) 37562306a36Sopenharmony_ci return -ENOMEM; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci init_job_desc(desc, 0); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci key_dma = dma_map_single(jrdev, key, *keylen, DMA_BIDIRECTIONAL); 38062306a36Sopenharmony_ci if (dma_mapping_error(jrdev, key_dma)) { 38162306a36Sopenharmony_ci dev_err(jrdev, "unable to map key memory\n"); 38262306a36Sopenharmony_ci kfree(desc); 38362306a36Sopenharmony_ci return -ENOMEM; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci /* Job descriptor to perform unkeyed hash on key_in */ 38762306a36Sopenharmony_ci append_operation(desc, ctx->adata.algtype | OP_ALG_ENCRYPT | 38862306a36Sopenharmony_ci OP_ALG_AS_INITFINAL); 38962306a36Sopenharmony_ci append_seq_in_ptr(desc, key_dma, *keylen, 0); 39062306a36Sopenharmony_ci append_seq_fifo_load(desc, *keylen, FIFOLD_CLASS_CLASS2 | 39162306a36Sopenharmony_ci FIFOLD_TYPE_LAST2 | FIFOLD_TYPE_MSG); 39262306a36Sopenharmony_ci append_seq_out_ptr(desc, key_dma, digestsize, 0); 39362306a36Sopenharmony_ci append_seq_store(desc, digestsize, LDST_CLASS_2_CCB | 39462306a36Sopenharmony_ci LDST_SRCDST_BYTE_CONTEXT); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci print_hex_dump_debug("key_in@"__stringify(__LINE__)": ", 39762306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, key, *keylen, 1); 39862306a36Sopenharmony_ci print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ", 39962306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 40062306a36Sopenharmony_ci 1); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci result.err = 0; 40362306a36Sopenharmony_ci init_completion(&result.completion); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci ret = caam_jr_enqueue(jrdev, desc, split_key_done, &result); 40662306a36Sopenharmony_ci if (ret == -EINPROGRESS) { 40762306a36Sopenharmony_ci /* in progress */ 40862306a36Sopenharmony_ci wait_for_completion(&result.completion); 40962306a36Sopenharmony_ci ret = result.err; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci print_hex_dump_debug("digested key@"__stringify(__LINE__)": ", 41262306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, key, 41362306a36Sopenharmony_ci digestsize, 1); 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci dma_unmap_single(jrdev, key_dma, *keylen, DMA_BIDIRECTIONAL); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci *keylen = digestsize; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci kfree(desc); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci return ret; 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic int ahash_setkey(struct crypto_ahash *ahash, 42562306a36Sopenharmony_ci const u8 *key, unsigned int keylen) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci struct caam_hash_ctx *ctx = crypto_ahash_ctx_dma(ahash); 42862306a36Sopenharmony_ci struct device *jrdev = ctx->jrdev; 42962306a36Sopenharmony_ci int blocksize = crypto_tfm_alg_blocksize(&ahash->base); 43062306a36Sopenharmony_ci int digestsize = crypto_ahash_digestsize(ahash); 43162306a36Sopenharmony_ci struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctx->jrdev->parent); 43262306a36Sopenharmony_ci int ret; 43362306a36Sopenharmony_ci u8 *hashed_key = NULL; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci dev_dbg(jrdev, "keylen %d\n", keylen); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci if (keylen > blocksize) { 43862306a36Sopenharmony_ci unsigned int aligned_len = 43962306a36Sopenharmony_ci ALIGN(keylen, dma_get_cache_alignment()); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci if (aligned_len < keylen) 44262306a36Sopenharmony_ci return -EOVERFLOW; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci hashed_key = kmemdup(key, keylen, GFP_KERNEL); 44562306a36Sopenharmony_ci if (!hashed_key) 44662306a36Sopenharmony_ci return -ENOMEM; 44762306a36Sopenharmony_ci ret = hash_digest_key(ctx, &keylen, hashed_key, digestsize); 44862306a36Sopenharmony_ci if (ret) 44962306a36Sopenharmony_ci goto bad_free_key; 45062306a36Sopenharmony_ci key = hashed_key; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* 45462306a36Sopenharmony_ci * If DKP is supported, use it in the shared descriptor to generate 45562306a36Sopenharmony_ci * the split key. 45662306a36Sopenharmony_ci */ 45762306a36Sopenharmony_ci if (ctrlpriv->era >= 6) { 45862306a36Sopenharmony_ci ctx->adata.key_inline = true; 45962306a36Sopenharmony_ci ctx->adata.keylen = keylen; 46062306a36Sopenharmony_ci ctx->adata.keylen_pad = split_key_len(ctx->adata.algtype & 46162306a36Sopenharmony_ci OP_ALG_ALGSEL_MASK); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci if (ctx->adata.keylen_pad > CAAM_MAX_HASH_KEY_SIZE) 46462306a36Sopenharmony_ci goto bad_free_key; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci memcpy(ctx->key, key, keylen); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci /* 46962306a36Sopenharmony_ci * In case |user key| > |derived key|, using DKP<imm,imm> 47062306a36Sopenharmony_ci * would result in invalid opcodes (last bytes of user key) in 47162306a36Sopenharmony_ci * the resulting descriptor. Use DKP<ptr,imm> instead => both 47262306a36Sopenharmony_ci * virtual and dma key addresses are needed. 47362306a36Sopenharmony_ci */ 47462306a36Sopenharmony_ci if (keylen > ctx->adata.keylen_pad) 47562306a36Sopenharmony_ci dma_sync_single_for_device(ctx->jrdev, 47662306a36Sopenharmony_ci ctx->adata.key_dma, 47762306a36Sopenharmony_ci ctx->adata.keylen_pad, 47862306a36Sopenharmony_ci DMA_TO_DEVICE); 47962306a36Sopenharmony_ci } else { 48062306a36Sopenharmony_ci ret = gen_split_key(ctx->jrdev, ctx->key, &ctx->adata, key, 48162306a36Sopenharmony_ci keylen, CAAM_MAX_HASH_KEY_SIZE); 48262306a36Sopenharmony_ci if (ret) 48362306a36Sopenharmony_ci goto bad_free_key; 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci kfree(hashed_key); 48762306a36Sopenharmony_ci return ahash_set_sh_desc(ahash); 48862306a36Sopenharmony_ci bad_free_key: 48962306a36Sopenharmony_ci kfree(hashed_key); 49062306a36Sopenharmony_ci return -EINVAL; 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic int axcbc_setkey(struct crypto_ahash *ahash, const u8 *key, 49462306a36Sopenharmony_ci unsigned int keylen) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci struct caam_hash_ctx *ctx = crypto_ahash_ctx_dma(ahash); 49762306a36Sopenharmony_ci struct device *jrdev = ctx->jrdev; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci if (keylen != AES_KEYSIZE_128) 50062306a36Sopenharmony_ci return -EINVAL; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci memcpy(ctx->key, key, keylen); 50362306a36Sopenharmony_ci dma_sync_single_for_device(jrdev, ctx->adata.key_dma, keylen, 50462306a36Sopenharmony_ci DMA_TO_DEVICE); 50562306a36Sopenharmony_ci ctx->adata.keylen = keylen; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci print_hex_dump_debug("axcbc ctx.key@" __stringify(__LINE__)" : ", 50862306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, keylen, 1); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci return axcbc_set_sh_desc(ahash); 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_cistatic int acmac_setkey(struct crypto_ahash *ahash, const u8 *key, 51462306a36Sopenharmony_ci unsigned int keylen) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci struct caam_hash_ctx *ctx = crypto_ahash_ctx_dma(ahash); 51762306a36Sopenharmony_ci int err; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci err = aes_check_keylen(keylen); 52062306a36Sopenharmony_ci if (err) 52162306a36Sopenharmony_ci return err; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci /* key is immediate data for all cmac shared descriptors */ 52462306a36Sopenharmony_ci ctx->adata.key_virt = key; 52562306a36Sopenharmony_ci ctx->adata.keylen = keylen; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci print_hex_dump_debug("acmac ctx.key@" __stringify(__LINE__)" : ", 52862306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci return acmac_set_sh_desc(ahash); 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci/* 53462306a36Sopenharmony_ci * ahash_edesc - s/w-extended ahash descriptor 53562306a36Sopenharmony_ci * @sec4_sg_dma: physical mapped address of h/w link table 53662306a36Sopenharmony_ci * @src_nents: number of segments in input scatterlist 53762306a36Sopenharmony_ci * @sec4_sg_bytes: length of dma mapped sec4_sg space 53862306a36Sopenharmony_ci * @bklog: stored to determine if the request needs backlog 53962306a36Sopenharmony_ci * @hw_desc: the h/w job descriptor followed by any referenced link tables 54062306a36Sopenharmony_ci * @sec4_sg: h/w link table 54162306a36Sopenharmony_ci */ 54262306a36Sopenharmony_cistruct ahash_edesc { 54362306a36Sopenharmony_ci dma_addr_t sec4_sg_dma; 54462306a36Sopenharmony_ci int src_nents; 54562306a36Sopenharmony_ci int sec4_sg_bytes; 54662306a36Sopenharmony_ci bool bklog; 54762306a36Sopenharmony_ci u32 hw_desc[DESC_JOB_IO_LEN_MAX / sizeof(u32)] ____cacheline_aligned; 54862306a36Sopenharmony_ci struct sec4_sg_entry sec4_sg[]; 54962306a36Sopenharmony_ci}; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cistatic inline void ahash_unmap(struct device *dev, 55262306a36Sopenharmony_ci struct ahash_edesc *edesc, 55362306a36Sopenharmony_ci struct ahash_request *req, int dst_len) 55462306a36Sopenharmony_ci{ 55562306a36Sopenharmony_ci struct caam_hash_state *state = ahash_request_ctx_dma(req); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (edesc->src_nents) 55862306a36Sopenharmony_ci dma_unmap_sg(dev, req->src, edesc->src_nents, DMA_TO_DEVICE); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci if (edesc->sec4_sg_bytes) 56162306a36Sopenharmony_ci dma_unmap_single(dev, edesc->sec4_sg_dma, 56262306a36Sopenharmony_ci edesc->sec4_sg_bytes, DMA_TO_DEVICE); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci if (state->buf_dma) { 56562306a36Sopenharmony_ci dma_unmap_single(dev, state->buf_dma, state->buflen, 56662306a36Sopenharmony_ci DMA_TO_DEVICE); 56762306a36Sopenharmony_ci state->buf_dma = 0; 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cistatic inline void ahash_unmap_ctx(struct device *dev, 57262306a36Sopenharmony_ci struct ahash_edesc *edesc, 57362306a36Sopenharmony_ci struct ahash_request *req, int dst_len, u32 flag) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci struct caam_hash_state *state = ahash_request_ctx_dma(req); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci if (state->ctx_dma) { 57862306a36Sopenharmony_ci dma_unmap_single(dev, state->ctx_dma, state->ctx_dma_len, flag); 57962306a36Sopenharmony_ci state->ctx_dma = 0; 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci ahash_unmap(dev, edesc, req, dst_len); 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_cistatic inline void ahash_done_cpy(struct device *jrdev, u32 *desc, u32 err, 58562306a36Sopenharmony_ci void *context, enum dma_data_direction dir) 58662306a36Sopenharmony_ci{ 58762306a36Sopenharmony_ci struct ahash_request *req = context; 58862306a36Sopenharmony_ci struct caam_drv_private_jr *jrp = dev_get_drvdata(jrdev); 58962306a36Sopenharmony_ci struct ahash_edesc *edesc; 59062306a36Sopenharmony_ci struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); 59162306a36Sopenharmony_ci int digestsize = crypto_ahash_digestsize(ahash); 59262306a36Sopenharmony_ci struct caam_hash_state *state = ahash_request_ctx_dma(req); 59362306a36Sopenharmony_ci struct caam_hash_ctx *ctx = crypto_ahash_ctx_dma(ahash); 59462306a36Sopenharmony_ci int ecode = 0; 59562306a36Sopenharmony_ci bool has_bklog; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci edesc = state->edesc; 60062306a36Sopenharmony_ci has_bklog = edesc->bklog; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci if (err) 60362306a36Sopenharmony_ci ecode = caam_jr_strstatus(jrdev, err); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci ahash_unmap_ctx(jrdev, edesc, req, digestsize, dir); 60662306a36Sopenharmony_ci memcpy(req->result, state->caam_ctx, digestsize); 60762306a36Sopenharmony_ci kfree(edesc); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci print_hex_dump_debug("ctx@"__stringify(__LINE__)": ", 61062306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx, 61162306a36Sopenharmony_ci ctx->ctx_len, 1); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci /* 61462306a36Sopenharmony_ci * If no backlog flag, the completion of the request is done 61562306a36Sopenharmony_ci * by CAAM, not crypto engine. 61662306a36Sopenharmony_ci */ 61762306a36Sopenharmony_ci if (!has_bklog) 61862306a36Sopenharmony_ci ahash_request_complete(req, ecode); 61962306a36Sopenharmony_ci else 62062306a36Sopenharmony_ci crypto_finalize_hash_request(jrp->engine, req, ecode); 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_cistatic void ahash_done(struct device *jrdev, u32 *desc, u32 err, 62462306a36Sopenharmony_ci void *context) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci ahash_done_cpy(jrdev, desc, err, context, DMA_FROM_DEVICE); 62762306a36Sopenharmony_ci} 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_cistatic void ahash_done_ctx_src(struct device *jrdev, u32 *desc, u32 err, 63062306a36Sopenharmony_ci void *context) 63162306a36Sopenharmony_ci{ 63262306a36Sopenharmony_ci ahash_done_cpy(jrdev, desc, err, context, DMA_BIDIRECTIONAL); 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic inline void ahash_done_switch(struct device *jrdev, u32 *desc, u32 err, 63662306a36Sopenharmony_ci void *context, enum dma_data_direction dir) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci struct ahash_request *req = context; 63962306a36Sopenharmony_ci struct caam_drv_private_jr *jrp = dev_get_drvdata(jrdev); 64062306a36Sopenharmony_ci struct ahash_edesc *edesc; 64162306a36Sopenharmony_ci struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); 64262306a36Sopenharmony_ci struct caam_hash_ctx *ctx = crypto_ahash_ctx_dma(ahash); 64362306a36Sopenharmony_ci struct caam_hash_state *state = ahash_request_ctx_dma(req); 64462306a36Sopenharmony_ci int digestsize = crypto_ahash_digestsize(ahash); 64562306a36Sopenharmony_ci int ecode = 0; 64662306a36Sopenharmony_ci bool has_bklog; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci edesc = state->edesc; 65162306a36Sopenharmony_ci has_bklog = edesc->bklog; 65262306a36Sopenharmony_ci if (err) 65362306a36Sopenharmony_ci ecode = caam_jr_strstatus(jrdev, err); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci ahash_unmap_ctx(jrdev, edesc, req, ctx->ctx_len, dir); 65662306a36Sopenharmony_ci kfree(edesc); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci scatterwalk_map_and_copy(state->buf, req->src, 65962306a36Sopenharmony_ci req->nbytes - state->next_buflen, 66062306a36Sopenharmony_ci state->next_buflen, 0); 66162306a36Sopenharmony_ci state->buflen = state->next_buflen; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci print_hex_dump_debug("buf@" __stringify(__LINE__)": ", 66462306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, state->buf, 66562306a36Sopenharmony_ci state->buflen, 1); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci print_hex_dump_debug("ctx@"__stringify(__LINE__)": ", 66862306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx, 66962306a36Sopenharmony_ci ctx->ctx_len, 1); 67062306a36Sopenharmony_ci if (req->result) 67162306a36Sopenharmony_ci print_hex_dump_debug("result@"__stringify(__LINE__)": ", 67262306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, req->result, 67362306a36Sopenharmony_ci digestsize, 1); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci /* 67662306a36Sopenharmony_ci * If no backlog flag, the completion of the request is done 67762306a36Sopenharmony_ci * by CAAM, not crypto engine. 67862306a36Sopenharmony_ci */ 67962306a36Sopenharmony_ci if (!has_bklog) 68062306a36Sopenharmony_ci ahash_request_complete(req, ecode); 68162306a36Sopenharmony_ci else 68262306a36Sopenharmony_ci crypto_finalize_hash_request(jrp->engine, req, ecode); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_cistatic void ahash_done_bi(struct device *jrdev, u32 *desc, u32 err, 68762306a36Sopenharmony_ci void *context) 68862306a36Sopenharmony_ci{ 68962306a36Sopenharmony_ci ahash_done_switch(jrdev, desc, err, context, DMA_BIDIRECTIONAL); 69062306a36Sopenharmony_ci} 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_cistatic void ahash_done_ctx_dst(struct device *jrdev, u32 *desc, u32 err, 69362306a36Sopenharmony_ci void *context) 69462306a36Sopenharmony_ci{ 69562306a36Sopenharmony_ci ahash_done_switch(jrdev, desc, err, context, DMA_FROM_DEVICE); 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci/* 69962306a36Sopenharmony_ci * Allocate an enhanced descriptor, which contains the hardware descriptor 70062306a36Sopenharmony_ci * and space for hardware scatter table containing sg_num entries. 70162306a36Sopenharmony_ci */ 70262306a36Sopenharmony_cistatic struct ahash_edesc *ahash_edesc_alloc(struct ahash_request *req, 70362306a36Sopenharmony_ci int sg_num, u32 *sh_desc, 70462306a36Sopenharmony_ci dma_addr_t sh_desc_dma) 70562306a36Sopenharmony_ci{ 70662306a36Sopenharmony_ci struct caam_hash_state *state = ahash_request_ctx_dma(req); 70762306a36Sopenharmony_ci gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? 70862306a36Sopenharmony_ci GFP_KERNEL : GFP_ATOMIC; 70962306a36Sopenharmony_ci struct ahash_edesc *edesc; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci edesc = kzalloc(struct_size(edesc, sec4_sg, sg_num), flags); 71262306a36Sopenharmony_ci if (!edesc) 71362306a36Sopenharmony_ci return NULL; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci state->edesc = edesc; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci init_job_desc_shared(edesc->hw_desc, sh_desc_dma, desc_len(sh_desc), 71862306a36Sopenharmony_ci HDR_SHARE_DEFER | HDR_REVERSE); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci return edesc; 72162306a36Sopenharmony_ci} 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_cistatic int ahash_edesc_add_src(struct caam_hash_ctx *ctx, 72462306a36Sopenharmony_ci struct ahash_edesc *edesc, 72562306a36Sopenharmony_ci struct ahash_request *req, int nents, 72662306a36Sopenharmony_ci unsigned int first_sg, 72762306a36Sopenharmony_ci unsigned int first_bytes, size_t to_hash) 72862306a36Sopenharmony_ci{ 72962306a36Sopenharmony_ci dma_addr_t src_dma; 73062306a36Sopenharmony_ci u32 options; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci if (nents > 1 || first_sg) { 73362306a36Sopenharmony_ci struct sec4_sg_entry *sg = edesc->sec4_sg; 73462306a36Sopenharmony_ci unsigned int sgsize = sizeof(*sg) * 73562306a36Sopenharmony_ci pad_sg_nents(first_sg + nents); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci sg_to_sec4_sg_last(req->src, to_hash, sg + first_sg, 0); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci src_dma = dma_map_single(ctx->jrdev, sg, sgsize, DMA_TO_DEVICE); 74062306a36Sopenharmony_ci if (dma_mapping_error(ctx->jrdev, src_dma)) { 74162306a36Sopenharmony_ci dev_err(ctx->jrdev, "unable to map S/G table\n"); 74262306a36Sopenharmony_ci return -ENOMEM; 74362306a36Sopenharmony_ci } 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci edesc->sec4_sg_bytes = sgsize; 74662306a36Sopenharmony_ci edesc->sec4_sg_dma = src_dma; 74762306a36Sopenharmony_ci options = LDST_SGF; 74862306a36Sopenharmony_ci } else { 74962306a36Sopenharmony_ci src_dma = sg_dma_address(req->src); 75062306a36Sopenharmony_ci options = 0; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci append_seq_in_ptr(edesc->hw_desc, src_dma, first_bytes + to_hash, 75462306a36Sopenharmony_ci options); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci return 0; 75762306a36Sopenharmony_ci} 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_cistatic int ahash_do_one_req(struct crypto_engine *engine, void *areq) 76062306a36Sopenharmony_ci{ 76162306a36Sopenharmony_ci struct ahash_request *req = ahash_request_cast(areq); 76262306a36Sopenharmony_ci struct caam_hash_ctx *ctx = crypto_ahash_ctx_dma(crypto_ahash_reqtfm(req)); 76362306a36Sopenharmony_ci struct caam_hash_state *state = ahash_request_ctx_dma(req); 76462306a36Sopenharmony_ci struct device *jrdev = ctx->jrdev; 76562306a36Sopenharmony_ci u32 *desc = state->edesc->hw_desc; 76662306a36Sopenharmony_ci int ret; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci state->edesc->bklog = true; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci ret = caam_jr_enqueue(jrdev, desc, state->ahash_op_done, req); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci if (ret == -ENOSPC && engine->retry_support) 77362306a36Sopenharmony_ci return ret; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci if (ret != -EINPROGRESS) { 77662306a36Sopenharmony_ci ahash_unmap(jrdev, state->edesc, req, 0); 77762306a36Sopenharmony_ci kfree(state->edesc); 77862306a36Sopenharmony_ci } else { 77962306a36Sopenharmony_ci ret = 0; 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci return ret; 78362306a36Sopenharmony_ci} 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_cistatic int ahash_enqueue_req(struct device *jrdev, 78662306a36Sopenharmony_ci void (*cbk)(struct device *jrdev, u32 *desc, 78762306a36Sopenharmony_ci u32 err, void *context), 78862306a36Sopenharmony_ci struct ahash_request *req, 78962306a36Sopenharmony_ci int dst_len, enum dma_data_direction dir) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci struct caam_drv_private_jr *jrpriv = dev_get_drvdata(jrdev); 79262306a36Sopenharmony_ci struct caam_hash_state *state = ahash_request_ctx_dma(req); 79362306a36Sopenharmony_ci struct ahash_edesc *edesc = state->edesc; 79462306a36Sopenharmony_ci u32 *desc = edesc->hw_desc; 79562306a36Sopenharmony_ci int ret; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci state->ahash_op_done = cbk; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci /* 80062306a36Sopenharmony_ci * Only the backlog request are sent to crypto-engine since the others 80162306a36Sopenharmony_ci * can be handled by CAAM, if free, especially since JR has up to 1024 80262306a36Sopenharmony_ci * entries (more than the 10 entries from crypto-engine). 80362306a36Sopenharmony_ci */ 80462306a36Sopenharmony_ci if (req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG) 80562306a36Sopenharmony_ci ret = crypto_transfer_hash_request_to_engine(jrpriv->engine, 80662306a36Sopenharmony_ci req); 80762306a36Sopenharmony_ci else 80862306a36Sopenharmony_ci ret = caam_jr_enqueue(jrdev, desc, cbk, req); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci if ((ret != -EINPROGRESS) && (ret != -EBUSY)) { 81162306a36Sopenharmony_ci ahash_unmap_ctx(jrdev, edesc, req, dst_len, dir); 81262306a36Sopenharmony_ci kfree(edesc); 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci return ret; 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci/* submit update job descriptor */ 81962306a36Sopenharmony_cistatic int ahash_update_ctx(struct ahash_request *req) 82062306a36Sopenharmony_ci{ 82162306a36Sopenharmony_ci struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); 82262306a36Sopenharmony_ci struct caam_hash_ctx *ctx = crypto_ahash_ctx_dma(ahash); 82362306a36Sopenharmony_ci struct caam_hash_state *state = ahash_request_ctx_dma(req); 82462306a36Sopenharmony_ci struct device *jrdev = ctx->jrdev; 82562306a36Sopenharmony_ci u8 *buf = state->buf; 82662306a36Sopenharmony_ci int *buflen = &state->buflen; 82762306a36Sopenharmony_ci int *next_buflen = &state->next_buflen; 82862306a36Sopenharmony_ci int blocksize = crypto_ahash_blocksize(ahash); 82962306a36Sopenharmony_ci int in_len = *buflen + req->nbytes, to_hash; 83062306a36Sopenharmony_ci u32 *desc; 83162306a36Sopenharmony_ci int src_nents, mapped_nents, sec4_sg_bytes, sec4_sg_src_index; 83262306a36Sopenharmony_ci struct ahash_edesc *edesc; 83362306a36Sopenharmony_ci int ret = 0; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci *next_buflen = in_len & (blocksize - 1); 83662306a36Sopenharmony_ci to_hash = in_len - *next_buflen; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci /* 83962306a36Sopenharmony_ci * For XCBC and CMAC, if to_hash is multiple of block size, 84062306a36Sopenharmony_ci * keep last block in internal buffer 84162306a36Sopenharmony_ci */ 84262306a36Sopenharmony_ci if ((is_xcbc_aes(ctx->adata.algtype) || 84362306a36Sopenharmony_ci is_cmac_aes(ctx->adata.algtype)) && to_hash >= blocksize && 84462306a36Sopenharmony_ci (*next_buflen == 0)) { 84562306a36Sopenharmony_ci *next_buflen = blocksize; 84662306a36Sopenharmony_ci to_hash -= blocksize; 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci if (to_hash) { 85062306a36Sopenharmony_ci int pad_nents; 85162306a36Sopenharmony_ci int src_len = req->nbytes - *next_buflen; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci src_nents = sg_nents_for_len(req->src, src_len); 85462306a36Sopenharmony_ci if (src_nents < 0) { 85562306a36Sopenharmony_ci dev_err(jrdev, "Invalid number of src SG.\n"); 85662306a36Sopenharmony_ci return src_nents; 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci if (src_nents) { 86062306a36Sopenharmony_ci mapped_nents = dma_map_sg(jrdev, req->src, src_nents, 86162306a36Sopenharmony_ci DMA_TO_DEVICE); 86262306a36Sopenharmony_ci if (!mapped_nents) { 86362306a36Sopenharmony_ci dev_err(jrdev, "unable to DMA map source\n"); 86462306a36Sopenharmony_ci return -ENOMEM; 86562306a36Sopenharmony_ci } 86662306a36Sopenharmony_ci } else { 86762306a36Sopenharmony_ci mapped_nents = 0; 86862306a36Sopenharmony_ci } 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci sec4_sg_src_index = 1 + (*buflen ? 1 : 0); 87162306a36Sopenharmony_ci pad_nents = pad_sg_nents(sec4_sg_src_index + mapped_nents); 87262306a36Sopenharmony_ci sec4_sg_bytes = pad_nents * sizeof(struct sec4_sg_entry); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci /* 87562306a36Sopenharmony_ci * allocate space for base edesc and hw desc commands, 87662306a36Sopenharmony_ci * link tables 87762306a36Sopenharmony_ci */ 87862306a36Sopenharmony_ci edesc = ahash_edesc_alloc(req, pad_nents, ctx->sh_desc_update, 87962306a36Sopenharmony_ci ctx->sh_desc_update_dma); 88062306a36Sopenharmony_ci if (!edesc) { 88162306a36Sopenharmony_ci dma_unmap_sg(jrdev, req->src, src_nents, DMA_TO_DEVICE); 88262306a36Sopenharmony_ci return -ENOMEM; 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci edesc->src_nents = src_nents; 88662306a36Sopenharmony_ci edesc->sec4_sg_bytes = sec4_sg_bytes; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci ret = ctx_map_to_sec4_sg(jrdev, state, ctx->ctx_len, 88962306a36Sopenharmony_ci edesc->sec4_sg, DMA_BIDIRECTIONAL); 89062306a36Sopenharmony_ci if (ret) 89162306a36Sopenharmony_ci goto unmap_ctx; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci ret = buf_map_to_sec4_sg(jrdev, edesc->sec4_sg + 1, state); 89462306a36Sopenharmony_ci if (ret) 89562306a36Sopenharmony_ci goto unmap_ctx; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci if (mapped_nents) 89862306a36Sopenharmony_ci sg_to_sec4_sg_last(req->src, src_len, 89962306a36Sopenharmony_ci edesc->sec4_sg + sec4_sg_src_index, 90062306a36Sopenharmony_ci 0); 90162306a36Sopenharmony_ci else 90262306a36Sopenharmony_ci sg_to_sec4_set_last(edesc->sec4_sg + sec4_sg_src_index - 90362306a36Sopenharmony_ci 1); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci desc = edesc->hw_desc; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, 90862306a36Sopenharmony_ci sec4_sg_bytes, 90962306a36Sopenharmony_ci DMA_TO_DEVICE); 91062306a36Sopenharmony_ci if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) { 91162306a36Sopenharmony_ci dev_err(jrdev, "unable to map S/G table\n"); 91262306a36Sopenharmony_ci ret = -ENOMEM; 91362306a36Sopenharmony_ci goto unmap_ctx; 91462306a36Sopenharmony_ci } 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci append_seq_in_ptr(desc, edesc->sec4_sg_dma, ctx->ctx_len + 91762306a36Sopenharmony_ci to_hash, LDST_SGF); 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci append_seq_out_ptr(desc, state->ctx_dma, ctx->ctx_len, 0); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ", 92262306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, desc, 92362306a36Sopenharmony_ci desc_bytes(desc), 1); 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci ret = ahash_enqueue_req(jrdev, ahash_done_bi, req, 92662306a36Sopenharmony_ci ctx->ctx_len, DMA_BIDIRECTIONAL); 92762306a36Sopenharmony_ci } else if (*next_buflen) { 92862306a36Sopenharmony_ci scatterwalk_map_and_copy(buf + *buflen, req->src, 0, 92962306a36Sopenharmony_ci req->nbytes, 0); 93062306a36Sopenharmony_ci *buflen = *next_buflen; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci print_hex_dump_debug("buf@" __stringify(__LINE__)": ", 93362306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, buf, 93462306a36Sopenharmony_ci *buflen, 1); 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci return ret; 93862306a36Sopenharmony_ciunmap_ctx: 93962306a36Sopenharmony_ci ahash_unmap_ctx(jrdev, edesc, req, ctx->ctx_len, DMA_BIDIRECTIONAL); 94062306a36Sopenharmony_ci kfree(edesc); 94162306a36Sopenharmony_ci return ret; 94262306a36Sopenharmony_ci} 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_cistatic int ahash_final_ctx(struct ahash_request *req) 94562306a36Sopenharmony_ci{ 94662306a36Sopenharmony_ci struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); 94762306a36Sopenharmony_ci struct caam_hash_ctx *ctx = crypto_ahash_ctx_dma(ahash); 94862306a36Sopenharmony_ci struct caam_hash_state *state = ahash_request_ctx_dma(req); 94962306a36Sopenharmony_ci struct device *jrdev = ctx->jrdev; 95062306a36Sopenharmony_ci int buflen = state->buflen; 95162306a36Sopenharmony_ci u32 *desc; 95262306a36Sopenharmony_ci int sec4_sg_bytes; 95362306a36Sopenharmony_ci int digestsize = crypto_ahash_digestsize(ahash); 95462306a36Sopenharmony_ci struct ahash_edesc *edesc; 95562306a36Sopenharmony_ci int ret; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci sec4_sg_bytes = pad_sg_nents(1 + (buflen ? 1 : 0)) * 95862306a36Sopenharmony_ci sizeof(struct sec4_sg_entry); 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci /* allocate space for base edesc and hw desc commands, link tables */ 96162306a36Sopenharmony_ci edesc = ahash_edesc_alloc(req, 4, ctx->sh_desc_fin, 96262306a36Sopenharmony_ci ctx->sh_desc_fin_dma); 96362306a36Sopenharmony_ci if (!edesc) 96462306a36Sopenharmony_ci return -ENOMEM; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci desc = edesc->hw_desc; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci edesc->sec4_sg_bytes = sec4_sg_bytes; 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci ret = ctx_map_to_sec4_sg(jrdev, state, ctx->ctx_len, 97162306a36Sopenharmony_ci edesc->sec4_sg, DMA_BIDIRECTIONAL); 97262306a36Sopenharmony_ci if (ret) 97362306a36Sopenharmony_ci goto unmap_ctx; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci ret = buf_map_to_sec4_sg(jrdev, edesc->sec4_sg + 1, state); 97662306a36Sopenharmony_ci if (ret) 97762306a36Sopenharmony_ci goto unmap_ctx; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci sg_to_sec4_set_last(edesc->sec4_sg + (buflen ? 1 : 0)); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, 98262306a36Sopenharmony_ci sec4_sg_bytes, DMA_TO_DEVICE); 98362306a36Sopenharmony_ci if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) { 98462306a36Sopenharmony_ci dev_err(jrdev, "unable to map S/G table\n"); 98562306a36Sopenharmony_ci ret = -ENOMEM; 98662306a36Sopenharmony_ci goto unmap_ctx; 98762306a36Sopenharmony_ci } 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci append_seq_in_ptr(desc, edesc->sec4_sg_dma, ctx->ctx_len + buflen, 99062306a36Sopenharmony_ci LDST_SGF); 99162306a36Sopenharmony_ci append_seq_out_ptr(desc, state->ctx_dma, digestsize, 0); 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ", 99462306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 99562306a36Sopenharmony_ci 1); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci return ahash_enqueue_req(jrdev, ahash_done_ctx_src, req, 99862306a36Sopenharmony_ci digestsize, DMA_BIDIRECTIONAL); 99962306a36Sopenharmony_ci unmap_ctx: 100062306a36Sopenharmony_ci ahash_unmap_ctx(jrdev, edesc, req, digestsize, DMA_BIDIRECTIONAL); 100162306a36Sopenharmony_ci kfree(edesc); 100262306a36Sopenharmony_ci return ret; 100362306a36Sopenharmony_ci} 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_cistatic int ahash_finup_ctx(struct ahash_request *req) 100662306a36Sopenharmony_ci{ 100762306a36Sopenharmony_ci struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); 100862306a36Sopenharmony_ci struct caam_hash_ctx *ctx = crypto_ahash_ctx_dma(ahash); 100962306a36Sopenharmony_ci struct caam_hash_state *state = ahash_request_ctx_dma(req); 101062306a36Sopenharmony_ci struct device *jrdev = ctx->jrdev; 101162306a36Sopenharmony_ci int buflen = state->buflen; 101262306a36Sopenharmony_ci u32 *desc; 101362306a36Sopenharmony_ci int sec4_sg_src_index; 101462306a36Sopenharmony_ci int src_nents, mapped_nents; 101562306a36Sopenharmony_ci int digestsize = crypto_ahash_digestsize(ahash); 101662306a36Sopenharmony_ci struct ahash_edesc *edesc; 101762306a36Sopenharmony_ci int ret; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci src_nents = sg_nents_for_len(req->src, req->nbytes); 102062306a36Sopenharmony_ci if (src_nents < 0) { 102162306a36Sopenharmony_ci dev_err(jrdev, "Invalid number of src SG.\n"); 102262306a36Sopenharmony_ci return src_nents; 102362306a36Sopenharmony_ci } 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci if (src_nents) { 102662306a36Sopenharmony_ci mapped_nents = dma_map_sg(jrdev, req->src, src_nents, 102762306a36Sopenharmony_ci DMA_TO_DEVICE); 102862306a36Sopenharmony_ci if (!mapped_nents) { 102962306a36Sopenharmony_ci dev_err(jrdev, "unable to DMA map source\n"); 103062306a36Sopenharmony_ci return -ENOMEM; 103162306a36Sopenharmony_ci } 103262306a36Sopenharmony_ci } else { 103362306a36Sopenharmony_ci mapped_nents = 0; 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci sec4_sg_src_index = 1 + (buflen ? 1 : 0); 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci /* allocate space for base edesc and hw desc commands, link tables */ 103962306a36Sopenharmony_ci edesc = ahash_edesc_alloc(req, sec4_sg_src_index + mapped_nents, 104062306a36Sopenharmony_ci ctx->sh_desc_fin, ctx->sh_desc_fin_dma); 104162306a36Sopenharmony_ci if (!edesc) { 104262306a36Sopenharmony_ci dma_unmap_sg(jrdev, req->src, src_nents, DMA_TO_DEVICE); 104362306a36Sopenharmony_ci return -ENOMEM; 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci desc = edesc->hw_desc; 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci edesc->src_nents = src_nents; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci ret = ctx_map_to_sec4_sg(jrdev, state, ctx->ctx_len, 105162306a36Sopenharmony_ci edesc->sec4_sg, DMA_BIDIRECTIONAL); 105262306a36Sopenharmony_ci if (ret) 105362306a36Sopenharmony_ci goto unmap_ctx; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci ret = buf_map_to_sec4_sg(jrdev, edesc->sec4_sg + 1, state); 105662306a36Sopenharmony_ci if (ret) 105762306a36Sopenharmony_ci goto unmap_ctx; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci ret = ahash_edesc_add_src(ctx, edesc, req, mapped_nents, 106062306a36Sopenharmony_ci sec4_sg_src_index, ctx->ctx_len + buflen, 106162306a36Sopenharmony_ci req->nbytes); 106262306a36Sopenharmony_ci if (ret) 106362306a36Sopenharmony_ci goto unmap_ctx; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci append_seq_out_ptr(desc, state->ctx_dma, digestsize, 0); 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ", 106862306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 106962306a36Sopenharmony_ci 1); 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci return ahash_enqueue_req(jrdev, ahash_done_ctx_src, req, 107262306a36Sopenharmony_ci digestsize, DMA_BIDIRECTIONAL); 107362306a36Sopenharmony_ci unmap_ctx: 107462306a36Sopenharmony_ci ahash_unmap_ctx(jrdev, edesc, req, digestsize, DMA_BIDIRECTIONAL); 107562306a36Sopenharmony_ci kfree(edesc); 107662306a36Sopenharmony_ci return ret; 107762306a36Sopenharmony_ci} 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_cistatic int ahash_digest(struct ahash_request *req) 108062306a36Sopenharmony_ci{ 108162306a36Sopenharmony_ci struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); 108262306a36Sopenharmony_ci struct caam_hash_ctx *ctx = crypto_ahash_ctx_dma(ahash); 108362306a36Sopenharmony_ci struct caam_hash_state *state = ahash_request_ctx_dma(req); 108462306a36Sopenharmony_ci struct device *jrdev = ctx->jrdev; 108562306a36Sopenharmony_ci u32 *desc; 108662306a36Sopenharmony_ci int digestsize = crypto_ahash_digestsize(ahash); 108762306a36Sopenharmony_ci int src_nents, mapped_nents; 108862306a36Sopenharmony_ci struct ahash_edesc *edesc; 108962306a36Sopenharmony_ci int ret; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci state->buf_dma = 0; 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci src_nents = sg_nents_for_len(req->src, req->nbytes); 109462306a36Sopenharmony_ci if (src_nents < 0) { 109562306a36Sopenharmony_ci dev_err(jrdev, "Invalid number of src SG.\n"); 109662306a36Sopenharmony_ci return src_nents; 109762306a36Sopenharmony_ci } 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci if (src_nents) { 110062306a36Sopenharmony_ci mapped_nents = dma_map_sg(jrdev, req->src, src_nents, 110162306a36Sopenharmony_ci DMA_TO_DEVICE); 110262306a36Sopenharmony_ci if (!mapped_nents) { 110362306a36Sopenharmony_ci dev_err(jrdev, "unable to map source for DMA\n"); 110462306a36Sopenharmony_ci return -ENOMEM; 110562306a36Sopenharmony_ci } 110662306a36Sopenharmony_ci } else { 110762306a36Sopenharmony_ci mapped_nents = 0; 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci /* allocate space for base edesc and hw desc commands, link tables */ 111162306a36Sopenharmony_ci edesc = ahash_edesc_alloc(req, mapped_nents > 1 ? mapped_nents : 0, 111262306a36Sopenharmony_ci ctx->sh_desc_digest, ctx->sh_desc_digest_dma); 111362306a36Sopenharmony_ci if (!edesc) { 111462306a36Sopenharmony_ci dma_unmap_sg(jrdev, req->src, src_nents, DMA_TO_DEVICE); 111562306a36Sopenharmony_ci return -ENOMEM; 111662306a36Sopenharmony_ci } 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci edesc->src_nents = src_nents; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci ret = ahash_edesc_add_src(ctx, edesc, req, mapped_nents, 0, 0, 112162306a36Sopenharmony_ci req->nbytes); 112262306a36Sopenharmony_ci if (ret) { 112362306a36Sopenharmony_ci ahash_unmap(jrdev, edesc, req, digestsize); 112462306a36Sopenharmony_ci kfree(edesc); 112562306a36Sopenharmony_ci return ret; 112662306a36Sopenharmony_ci } 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci desc = edesc->hw_desc; 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci ret = map_seq_out_ptr_ctx(desc, jrdev, state, digestsize); 113162306a36Sopenharmony_ci if (ret) { 113262306a36Sopenharmony_ci ahash_unmap(jrdev, edesc, req, digestsize); 113362306a36Sopenharmony_ci kfree(edesc); 113462306a36Sopenharmony_ci return -ENOMEM; 113562306a36Sopenharmony_ci } 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ", 113862306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 113962306a36Sopenharmony_ci 1); 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci return ahash_enqueue_req(jrdev, ahash_done, req, digestsize, 114262306a36Sopenharmony_ci DMA_FROM_DEVICE); 114362306a36Sopenharmony_ci} 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci/* submit ahash final if it the first job descriptor */ 114662306a36Sopenharmony_cistatic int ahash_final_no_ctx(struct ahash_request *req) 114762306a36Sopenharmony_ci{ 114862306a36Sopenharmony_ci struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); 114962306a36Sopenharmony_ci struct caam_hash_ctx *ctx = crypto_ahash_ctx_dma(ahash); 115062306a36Sopenharmony_ci struct caam_hash_state *state = ahash_request_ctx_dma(req); 115162306a36Sopenharmony_ci struct device *jrdev = ctx->jrdev; 115262306a36Sopenharmony_ci u8 *buf = state->buf; 115362306a36Sopenharmony_ci int buflen = state->buflen; 115462306a36Sopenharmony_ci u32 *desc; 115562306a36Sopenharmony_ci int digestsize = crypto_ahash_digestsize(ahash); 115662306a36Sopenharmony_ci struct ahash_edesc *edesc; 115762306a36Sopenharmony_ci int ret; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci /* allocate space for base edesc and hw desc commands, link tables */ 116062306a36Sopenharmony_ci edesc = ahash_edesc_alloc(req, 0, ctx->sh_desc_digest, 116162306a36Sopenharmony_ci ctx->sh_desc_digest_dma); 116262306a36Sopenharmony_ci if (!edesc) 116362306a36Sopenharmony_ci return -ENOMEM; 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci desc = edesc->hw_desc; 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci if (buflen) { 116862306a36Sopenharmony_ci state->buf_dma = dma_map_single(jrdev, buf, buflen, 116962306a36Sopenharmony_ci DMA_TO_DEVICE); 117062306a36Sopenharmony_ci if (dma_mapping_error(jrdev, state->buf_dma)) { 117162306a36Sopenharmony_ci dev_err(jrdev, "unable to map src\n"); 117262306a36Sopenharmony_ci goto unmap; 117362306a36Sopenharmony_ci } 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci append_seq_in_ptr(desc, state->buf_dma, buflen, 0); 117662306a36Sopenharmony_ci } 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci ret = map_seq_out_ptr_ctx(desc, jrdev, state, digestsize); 117962306a36Sopenharmony_ci if (ret) 118062306a36Sopenharmony_ci goto unmap; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ", 118362306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 118462306a36Sopenharmony_ci 1); 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci return ahash_enqueue_req(jrdev, ahash_done, req, 118762306a36Sopenharmony_ci digestsize, DMA_FROM_DEVICE); 118862306a36Sopenharmony_ci unmap: 118962306a36Sopenharmony_ci ahash_unmap(jrdev, edesc, req, digestsize); 119062306a36Sopenharmony_ci kfree(edesc); 119162306a36Sopenharmony_ci return -ENOMEM; 119262306a36Sopenharmony_ci} 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci/* submit ahash update if it the first job descriptor after update */ 119562306a36Sopenharmony_cistatic int ahash_update_no_ctx(struct ahash_request *req) 119662306a36Sopenharmony_ci{ 119762306a36Sopenharmony_ci struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); 119862306a36Sopenharmony_ci struct caam_hash_ctx *ctx = crypto_ahash_ctx_dma(ahash); 119962306a36Sopenharmony_ci struct caam_hash_state *state = ahash_request_ctx_dma(req); 120062306a36Sopenharmony_ci struct device *jrdev = ctx->jrdev; 120162306a36Sopenharmony_ci u8 *buf = state->buf; 120262306a36Sopenharmony_ci int *buflen = &state->buflen; 120362306a36Sopenharmony_ci int *next_buflen = &state->next_buflen; 120462306a36Sopenharmony_ci int blocksize = crypto_ahash_blocksize(ahash); 120562306a36Sopenharmony_ci int in_len = *buflen + req->nbytes, to_hash; 120662306a36Sopenharmony_ci int sec4_sg_bytes, src_nents, mapped_nents; 120762306a36Sopenharmony_ci struct ahash_edesc *edesc; 120862306a36Sopenharmony_ci u32 *desc; 120962306a36Sopenharmony_ci int ret = 0; 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci *next_buflen = in_len & (blocksize - 1); 121262306a36Sopenharmony_ci to_hash = in_len - *next_buflen; 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci /* 121562306a36Sopenharmony_ci * For XCBC and CMAC, if to_hash is multiple of block size, 121662306a36Sopenharmony_ci * keep last block in internal buffer 121762306a36Sopenharmony_ci */ 121862306a36Sopenharmony_ci if ((is_xcbc_aes(ctx->adata.algtype) || 121962306a36Sopenharmony_ci is_cmac_aes(ctx->adata.algtype)) && to_hash >= blocksize && 122062306a36Sopenharmony_ci (*next_buflen == 0)) { 122162306a36Sopenharmony_ci *next_buflen = blocksize; 122262306a36Sopenharmony_ci to_hash -= blocksize; 122362306a36Sopenharmony_ci } 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci if (to_hash) { 122662306a36Sopenharmony_ci int pad_nents; 122762306a36Sopenharmony_ci int src_len = req->nbytes - *next_buflen; 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci src_nents = sg_nents_for_len(req->src, src_len); 123062306a36Sopenharmony_ci if (src_nents < 0) { 123162306a36Sopenharmony_ci dev_err(jrdev, "Invalid number of src SG.\n"); 123262306a36Sopenharmony_ci return src_nents; 123362306a36Sopenharmony_ci } 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci if (src_nents) { 123662306a36Sopenharmony_ci mapped_nents = dma_map_sg(jrdev, req->src, src_nents, 123762306a36Sopenharmony_ci DMA_TO_DEVICE); 123862306a36Sopenharmony_ci if (!mapped_nents) { 123962306a36Sopenharmony_ci dev_err(jrdev, "unable to DMA map source\n"); 124062306a36Sopenharmony_ci return -ENOMEM; 124162306a36Sopenharmony_ci } 124262306a36Sopenharmony_ci } else { 124362306a36Sopenharmony_ci mapped_nents = 0; 124462306a36Sopenharmony_ci } 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci pad_nents = pad_sg_nents(1 + mapped_nents); 124762306a36Sopenharmony_ci sec4_sg_bytes = pad_nents * sizeof(struct sec4_sg_entry); 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci /* 125062306a36Sopenharmony_ci * allocate space for base edesc and hw desc commands, 125162306a36Sopenharmony_ci * link tables 125262306a36Sopenharmony_ci */ 125362306a36Sopenharmony_ci edesc = ahash_edesc_alloc(req, pad_nents, 125462306a36Sopenharmony_ci ctx->sh_desc_update_first, 125562306a36Sopenharmony_ci ctx->sh_desc_update_first_dma); 125662306a36Sopenharmony_ci if (!edesc) { 125762306a36Sopenharmony_ci dma_unmap_sg(jrdev, req->src, src_nents, DMA_TO_DEVICE); 125862306a36Sopenharmony_ci return -ENOMEM; 125962306a36Sopenharmony_ci } 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci edesc->src_nents = src_nents; 126262306a36Sopenharmony_ci edesc->sec4_sg_bytes = sec4_sg_bytes; 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci ret = buf_map_to_sec4_sg(jrdev, edesc->sec4_sg, state); 126562306a36Sopenharmony_ci if (ret) 126662306a36Sopenharmony_ci goto unmap_ctx; 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci sg_to_sec4_sg_last(req->src, src_len, edesc->sec4_sg + 1, 0); 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci desc = edesc->hw_desc; 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, 127362306a36Sopenharmony_ci sec4_sg_bytes, 127462306a36Sopenharmony_ci DMA_TO_DEVICE); 127562306a36Sopenharmony_ci if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) { 127662306a36Sopenharmony_ci dev_err(jrdev, "unable to map S/G table\n"); 127762306a36Sopenharmony_ci ret = -ENOMEM; 127862306a36Sopenharmony_ci goto unmap_ctx; 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci append_seq_in_ptr(desc, edesc->sec4_sg_dma, to_hash, LDST_SGF); 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci ret = map_seq_out_ptr_ctx(desc, jrdev, state, ctx->ctx_len); 128462306a36Sopenharmony_ci if (ret) 128562306a36Sopenharmony_ci goto unmap_ctx; 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ", 128862306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, desc, 128962306a36Sopenharmony_ci desc_bytes(desc), 1); 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci ret = ahash_enqueue_req(jrdev, ahash_done_ctx_dst, req, 129262306a36Sopenharmony_ci ctx->ctx_len, DMA_TO_DEVICE); 129362306a36Sopenharmony_ci if ((ret != -EINPROGRESS) && (ret != -EBUSY)) 129462306a36Sopenharmony_ci return ret; 129562306a36Sopenharmony_ci state->update = ahash_update_ctx; 129662306a36Sopenharmony_ci state->finup = ahash_finup_ctx; 129762306a36Sopenharmony_ci state->final = ahash_final_ctx; 129862306a36Sopenharmony_ci } else if (*next_buflen) { 129962306a36Sopenharmony_ci scatterwalk_map_and_copy(buf + *buflen, req->src, 0, 130062306a36Sopenharmony_ci req->nbytes, 0); 130162306a36Sopenharmony_ci *buflen = *next_buflen; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci print_hex_dump_debug("buf@" __stringify(__LINE__)": ", 130462306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, buf, 130562306a36Sopenharmony_ci *buflen, 1); 130662306a36Sopenharmony_ci } 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci return ret; 130962306a36Sopenharmony_ci unmap_ctx: 131062306a36Sopenharmony_ci ahash_unmap_ctx(jrdev, edesc, req, ctx->ctx_len, DMA_TO_DEVICE); 131162306a36Sopenharmony_ci kfree(edesc); 131262306a36Sopenharmony_ci return ret; 131362306a36Sopenharmony_ci} 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci/* submit ahash finup if it the first job descriptor after update */ 131662306a36Sopenharmony_cistatic int ahash_finup_no_ctx(struct ahash_request *req) 131762306a36Sopenharmony_ci{ 131862306a36Sopenharmony_ci struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); 131962306a36Sopenharmony_ci struct caam_hash_ctx *ctx = crypto_ahash_ctx_dma(ahash); 132062306a36Sopenharmony_ci struct caam_hash_state *state = ahash_request_ctx_dma(req); 132162306a36Sopenharmony_ci struct device *jrdev = ctx->jrdev; 132262306a36Sopenharmony_ci int buflen = state->buflen; 132362306a36Sopenharmony_ci u32 *desc; 132462306a36Sopenharmony_ci int sec4_sg_bytes, sec4_sg_src_index, src_nents, mapped_nents; 132562306a36Sopenharmony_ci int digestsize = crypto_ahash_digestsize(ahash); 132662306a36Sopenharmony_ci struct ahash_edesc *edesc; 132762306a36Sopenharmony_ci int ret; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci src_nents = sg_nents_for_len(req->src, req->nbytes); 133062306a36Sopenharmony_ci if (src_nents < 0) { 133162306a36Sopenharmony_ci dev_err(jrdev, "Invalid number of src SG.\n"); 133262306a36Sopenharmony_ci return src_nents; 133362306a36Sopenharmony_ci } 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci if (src_nents) { 133662306a36Sopenharmony_ci mapped_nents = dma_map_sg(jrdev, req->src, src_nents, 133762306a36Sopenharmony_ci DMA_TO_DEVICE); 133862306a36Sopenharmony_ci if (!mapped_nents) { 133962306a36Sopenharmony_ci dev_err(jrdev, "unable to DMA map source\n"); 134062306a36Sopenharmony_ci return -ENOMEM; 134162306a36Sopenharmony_ci } 134262306a36Sopenharmony_ci } else { 134362306a36Sopenharmony_ci mapped_nents = 0; 134462306a36Sopenharmony_ci } 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci sec4_sg_src_index = 2; 134762306a36Sopenharmony_ci sec4_sg_bytes = (sec4_sg_src_index + mapped_nents) * 134862306a36Sopenharmony_ci sizeof(struct sec4_sg_entry); 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci /* allocate space for base edesc and hw desc commands, link tables */ 135162306a36Sopenharmony_ci edesc = ahash_edesc_alloc(req, sec4_sg_src_index + mapped_nents, 135262306a36Sopenharmony_ci ctx->sh_desc_digest, ctx->sh_desc_digest_dma); 135362306a36Sopenharmony_ci if (!edesc) { 135462306a36Sopenharmony_ci dma_unmap_sg(jrdev, req->src, src_nents, DMA_TO_DEVICE); 135562306a36Sopenharmony_ci return -ENOMEM; 135662306a36Sopenharmony_ci } 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci desc = edesc->hw_desc; 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci edesc->src_nents = src_nents; 136162306a36Sopenharmony_ci edesc->sec4_sg_bytes = sec4_sg_bytes; 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci ret = buf_map_to_sec4_sg(jrdev, edesc->sec4_sg, state); 136462306a36Sopenharmony_ci if (ret) 136562306a36Sopenharmony_ci goto unmap; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci ret = ahash_edesc_add_src(ctx, edesc, req, mapped_nents, 1, buflen, 136862306a36Sopenharmony_ci req->nbytes); 136962306a36Sopenharmony_ci if (ret) { 137062306a36Sopenharmony_ci dev_err(jrdev, "unable to map S/G table\n"); 137162306a36Sopenharmony_ci goto unmap; 137262306a36Sopenharmony_ci } 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci ret = map_seq_out_ptr_ctx(desc, jrdev, state, digestsize); 137562306a36Sopenharmony_ci if (ret) 137662306a36Sopenharmony_ci goto unmap; 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ", 137962306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 138062306a36Sopenharmony_ci 1); 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci return ahash_enqueue_req(jrdev, ahash_done, req, 138362306a36Sopenharmony_ci digestsize, DMA_FROM_DEVICE); 138462306a36Sopenharmony_ci unmap: 138562306a36Sopenharmony_ci ahash_unmap(jrdev, edesc, req, digestsize); 138662306a36Sopenharmony_ci kfree(edesc); 138762306a36Sopenharmony_ci return -ENOMEM; 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci} 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci/* submit first update job descriptor after init */ 139262306a36Sopenharmony_cistatic int ahash_update_first(struct ahash_request *req) 139362306a36Sopenharmony_ci{ 139462306a36Sopenharmony_ci struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); 139562306a36Sopenharmony_ci struct caam_hash_ctx *ctx = crypto_ahash_ctx_dma(ahash); 139662306a36Sopenharmony_ci struct caam_hash_state *state = ahash_request_ctx_dma(req); 139762306a36Sopenharmony_ci struct device *jrdev = ctx->jrdev; 139862306a36Sopenharmony_ci u8 *buf = state->buf; 139962306a36Sopenharmony_ci int *buflen = &state->buflen; 140062306a36Sopenharmony_ci int *next_buflen = &state->next_buflen; 140162306a36Sopenharmony_ci int to_hash; 140262306a36Sopenharmony_ci int blocksize = crypto_ahash_blocksize(ahash); 140362306a36Sopenharmony_ci u32 *desc; 140462306a36Sopenharmony_ci int src_nents, mapped_nents; 140562306a36Sopenharmony_ci struct ahash_edesc *edesc; 140662306a36Sopenharmony_ci int ret = 0; 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci *next_buflen = req->nbytes & (blocksize - 1); 140962306a36Sopenharmony_ci to_hash = req->nbytes - *next_buflen; 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci /* 141262306a36Sopenharmony_ci * For XCBC and CMAC, if to_hash is multiple of block size, 141362306a36Sopenharmony_ci * keep last block in internal buffer 141462306a36Sopenharmony_ci */ 141562306a36Sopenharmony_ci if ((is_xcbc_aes(ctx->adata.algtype) || 141662306a36Sopenharmony_ci is_cmac_aes(ctx->adata.algtype)) && to_hash >= blocksize && 141762306a36Sopenharmony_ci (*next_buflen == 0)) { 141862306a36Sopenharmony_ci *next_buflen = blocksize; 141962306a36Sopenharmony_ci to_hash -= blocksize; 142062306a36Sopenharmony_ci } 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci if (to_hash) { 142362306a36Sopenharmony_ci src_nents = sg_nents_for_len(req->src, 142462306a36Sopenharmony_ci req->nbytes - *next_buflen); 142562306a36Sopenharmony_ci if (src_nents < 0) { 142662306a36Sopenharmony_ci dev_err(jrdev, "Invalid number of src SG.\n"); 142762306a36Sopenharmony_ci return src_nents; 142862306a36Sopenharmony_ci } 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci if (src_nents) { 143162306a36Sopenharmony_ci mapped_nents = dma_map_sg(jrdev, req->src, src_nents, 143262306a36Sopenharmony_ci DMA_TO_DEVICE); 143362306a36Sopenharmony_ci if (!mapped_nents) { 143462306a36Sopenharmony_ci dev_err(jrdev, "unable to map source for DMA\n"); 143562306a36Sopenharmony_ci return -ENOMEM; 143662306a36Sopenharmony_ci } 143762306a36Sopenharmony_ci } else { 143862306a36Sopenharmony_ci mapped_nents = 0; 143962306a36Sopenharmony_ci } 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci /* 144262306a36Sopenharmony_ci * allocate space for base edesc and hw desc commands, 144362306a36Sopenharmony_ci * link tables 144462306a36Sopenharmony_ci */ 144562306a36Sopenharmony_ci edesc = ahash_edesc_alloc(req, mapped_nents > 1 ? 144662306a36Sopenharmony_ci mapped_nents : 0, 144762306a36Sopenharmony_ci ctx->sh_desc_update_first, 144862306a36Sopenharmony_ci ctx->sh_desc_update_first_dma); 144962306a36Sopenharmony_ci if (!edesc) { 145062306a36Sopenharmony_ci dma_unmap_sg(jrdev, req->src, src_nents, DMA_TO_DEVICE); 145162306a36Sopenharmony_ci return -ENOMEM; 145262306a36Sopenharmony_ci } 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci edesc->src_nents = src_nents; 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci ret = ahash_edesc_add_src(ctx, edesc, req, mapped_nents, 0, 0, 145762306a36Sopenharmony_ci to_hash); 145862306a36Sopenharmony_ci if (ret) 145962306a36Sopenharmony_ci goto unmap_ctx; 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci desc = edesc->hw_desc; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci ret = map_seq_out_ptr_ctx(desc, jrdev, state, ctx->ctx_len); 146462306a36Sopenharmony_ci if (ret) 146562306a36Sopenharmony_ci goto unmap_ctx; 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ", 146862306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, desc, 146962306a36Sopenharmony_ci desc_bytes(desc), 1); 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci ret = ahash_enqueue_req(jrdev, ahash_done_ctx_dst, req, 147262306a36Sopenharmony_ci ctx->ctx_len, DMA_TO_DEVICE); 147362306a36Sopenharmony_ci if ((ret != -EINPROGRESS) && (ret != -EBUSY)) 147462306a36Sopenharmony_ci return ret; 147562306a36Sopenharmony_ci state->update = ahash_update_ctx; 147662306a36Sopenharmony_ci state->finup = ahash_finup_ctx; 147762306a36Sopenharmony_ci state->final = ahash_final_ctx; 147862306a36Sopenharmony_ci } else if (*next_buflen) { 147962306a36Sopenharmony_ci state->update = ahash_update_no_ctx; 148062306a36Sopenharmony_ci state->finup = ahash_finup_no_ctx; 148162306a36Sopenharmony_ci state->final = ahash_final_no_ctx; 148262306a36Sopenharmony_ci scatterwalk_map_and_copy(buf, req->src, 0, 148362306a36Sopenharmony_ci req->nbytes, 0); 148462306a36Sopenharmony_ci *buflen = *next_buflen; 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci print_hex_dump_debug("buf@" __stringify(__LINE__)": ", 148762306a36Sopenharmony_ci DUMP_PREFIX_ADDRESS, 16, 4, buf, 148862306a36Sopenharmony_ci *buflen, 1); 148962306a36Sopenharmony_ci } 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci return ret; 149262306a36Sopenharmony_ci unmap_ctx: 149362306a36Sopenharmony_ci ahash_unmap_ctx(jrdev, edesc, req, ctx->ctx_len, DMA_TO_DEVICE); 149462306a36Sopenharmony_ci kfree(edesc); 149562306a36Sopenharmony_ci return ret; 149662306a36Sopenharmony_ci} 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_cistatic int ahash_finup_first(struct ahash_request *req) 149962306a36Sopenharmony_ci{ 150062306a36Sopenharmony_ci return ahash_digest(req); 150162306a36Sopenharmony_ci} 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_cistatic int ahash_init(struct ahash_request *req) 150462306a36Sopenharmony_ci{ 150562306a36Sopenharmony_ci struct caam_hash_state *state = ahash_request_ctx_dma(req); 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci state->update = ahash_update_first; 150862306a36Sopenharmony_ci state->finup = ahash_finup_first; 150962306a36Sopenharmony_ci state->final = ahash_final_no_ctx; 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci state->ctx_dma = 0; 151262306a36Sopenharmony_ci state->ctx_dma_len = 0; 151362306a36Sopenharmony_ci state->buf_dma = 0; 151462306a36Sopenharmony_ci state->buflen = 0; 151562306a36Sopenharmony_ci state->next_buflen = 0; 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci return 0; 151862306a36Sopenharmony_ci} 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_cistatic int ahash_update(struct ahash_request *req) 152162306a36Sopenharmony_ci{ 152262306a36Sopenharmony_ci struct caam_hash_state *state = ahash_request_ctx_dma(req); 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci return state->update(req); 152562306a36Sopenharmony_ci} 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_cistatic int ahash_finup(struct ahash_request *req) 152862306a36Sopenharmony_ci{ 152962306a36Sopenharmony_ci struct caam_hash_state *state = ahash_request_ctx_dma(req); 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci return state->finup(req); 153262306a36Sopenharmony_ci} 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_cistatic int ahash_final(struct ahash_request *req) 153562306a36Sopenharmony_ci{ 153662306a36Sopenharmony_ci struct caam_hash_state *state = ahash_request_ctx_dma(req); 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci return state->final(req); 153962306a36Sopenharmony_ci} 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_cistatic int ahash_export(struct ahash_request *req, void *out) 154262306a36Sopenharmony_ci{ 154362306a36Sopenharmony_ci struct caam_hash_state *state = ahash_request_ctx_dma(req); 154462306a36Sopenharmony_ci struct caam_export_state *export = out; 154562306a36Sopenharmony_ci u8 *buf = state->buf; 154662306a36Sopenharmony_ci int len = state->buflen; 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci memcpy(export->buf, buf, len); 154962306a36Sopenharmony_ci memcpy(export->caam_ctx, state->caam_ctx, sizeof(export->caam_ctx)); 155062306a36Sopenharmony_ci export->buflen = len; 155162306a36Sopenharmony_ci export->update = state->update; 155262306a36Sopenharmony_ci export->final = state->final; 155362306a36Sopenharmony_ci export->finup = state->finup; 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci return 0; 155662306a36Sopenharmony_ci} 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_cistatic int ahash_import(struct ahash_request *req, const void *in) 155962306a36Sopenharmony_ci{ 156062306a36Sopenharmony_ci struct caam_hash_state *state = ahash_request_ctx_dma(req); 156162306a36Sopenharmony_ci const struct caam_export_state *export = in; 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci memset(state, 0, sizeof(*state)); 156462306a36Sopenharmony_ci memcpy(state->buf, export->buf, export->buflen); 156562306a36Sopenharmony_ci memcpy(state->caam_ctx, export->caam_ctx, sizeof(state->caam_ctx)); 156662306a36Sopenharmony_ci state->buflen = export->buflen; 156762306a36Sopenharmony_ci state->update = export->update; 156862306a36Sopenharmony_ci state->final = export->final; 156962306a36Sopenharmony_ci state->finup = export->finup; 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci return 0; 157262306a36Sopenharmony_ci} 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_cistruct caam_hash_template { 157562306a36Sopenharmony_ci char name[CRYPTO_MAX_ALG_NAME]; 157662306a36Sopenharmony_ci char driver_name[CRYPTO_MAX_ALG_NAME]; 157762306a36Sopenharmony_ci char hmac_name[CRYPTO_MAX_ALG_NAME]; 157862306a36Sopenharmony_ci char hmac_driver_name[CRYPTO_MAX_ALG_NAME]; 157962306a36Sopenharmony_ci unsigned int blocksize; 158062306a36Sopenharmony_ci struct ahash_alg template_ahash; 158162306a36Sopenharmony_ci u32 alg_type; 158262306a36Sopenharmony_ci}; 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci/* ahash descriptors */ 158562306a36Sopenharmony_cistatic struct caam_hash_template driver_hash[] = { 158662306a36Sopenharmony_ci { 158762306a36Sopenharmony_ci .name = "sha1", 158862306a36Sopenharmony_ci .driver_name = "sha1-caam", 158962306a36Sopenharmony_ci .hmac_name = "hmac(sha1)", 159062306a36Sopenharmony_ci .hmac_driver_name = "hmac-sha1-caam", 159162306a36Sopenharmony_ci .blocksize = SHA1_BLOCK_SIZE, 159262306a36Sopenharmony_ci .template_ahash = { 159362306a36Sopenharmony_ci .init = ahash_init, 159462306a36Sopenharmony_ci .update = ahash_update, 159562306a36Sopenharmony_ci .final = ahash_final, 159662306a36Sopenharmony_ci .finup = ahash_finup, 159762306a36Sopenharmony_ci .digest = ahash_digest, 159862306a36Sopenharmony_ci .export = ahash_export, 159962306a36Sopenharmony_ci .import = ahash_import, 160062306a36Sopenharmony_ci .setkey = ahash_setkey, 160162306a36Sopenharmony_ci .halg = { 160262306a36Sopenharmony_ci .digestsize = SHA1_DIGEST_SIZE, 160362306a36Sopenharmony_ci .statesize = sizeof(struct caam_export_state), 160462306a36Sopenharmony_ci }, 160562306a36Sopenharmony_ci }, 160662306a36Sopenharmony_ci .alg_type = OP_ALG_ALGSEL_SHA1, 160762306a36Sopenharmony_ci }, { 160862306a36Sopenharmony_ci .name = "sha224", 160962306a36Sopenharmony_ci .driver_name = "sha224-caam", 161062306a36Sopenharmony_ci .hmac_name = "hmac(sha224)", 161162306a36Sopenharmony_ci .hmac_driver_name = "hmac-sha224-caam", 161262306a36Sopenharmony_ci .blocksize = SHA224_BLOCK_SIZE, 161362306a36Sopenharmony_ci .template_ahash = { 161462306a36Sopenharmony_ci .init = ahash_init, 161562306a36Sopenharmony_ci .update = ahash_update, 161662306a36Sopenharmony_ci .final = ahash_final, 161762306a36Sopenharmony_ci .finup = ahash_finup, 161862306a36Sopenharmony_ci .digest = ahash_digest, 161962306a36Sopenharmony_ci .export = ahash_export, 162062306a36Sopenharmony_ci .import = ahash_import, 162162306a36Sopenharmony_ci .setkey = ahash_setkey, 162262306a36Sopenharmony_ci .halg = { 162362306a36Sopenharmony_ci .digestsize = SHA224_DIGEST_SIZE, 162462306a36Sopenharmony_ci .statesize = sizeof(struct caam_export_state), 162562306a36Sopenharmony_ci }, 162662306a36Sopenharmony_ci }, 162762306a36Sopenharmony_ci .alg_type = OP_ALG_ALGSEL_SHA224, 162862306a36Sopenharmony_ci }, { 162962306a36Sopenharmony_ci .name = "sha256", 163062306a36Sopenharmony_ci .driver_name = "sha256-caam", 163162306a36Sopenharmony_ci .hmac_name = "hmac(sha256)", 163262306a36Sopenharmony_ci .hmac_driver_name = "hmac-sha256-caam", 163362306a36Sopenharmony_ci .blocksize = SHA256_BLOCK_SIZE, 163462306a36Sopenharmony_ci .template_ahash = { 163562306a36Sopenharmony_ci .init = ahash_init, 163662306a36Sopenharmony_ci .update = ahash_update, 163762306a36Sopenharmony_ci .final = ahash_final, 163862306a36Sopenharmony_ci .finup = ahash_finup, 163962306a36Sopenharmony_ci .digest = ahash_digest, 164062306a36Sopenharmony_ci .export = ahash_export, 164162306a36Sopenharmony_ci .import = ahash_import, 164262306a36Sopenharmony_ci .setkey = ahash_setkey, 164362306a36Sopenharmony_ci .halg = { 164462306a36Sopenharmony_ci .digestsize = SHA256_DIGEST_SIZE, 164562306a36Sopenharmony_ci .statesize = sizeof(struct caam_export_state), 164662306a36Sopenharmony_ci }, 164762306a36Sopenharmony_ci }, 164862306a36Sopenharmony_ci .alg_type = OP_ALG_ALGSEL_SHA256, 164962306a36Sopenharmony_ci }, { 165062306a36Sopenharmony_ci .name = "sha384", 165162306a36Sopenharmony_ci .driver_name = "sha384-caam", 165262306a36Sopenharmony_ci .hmac_name = "hmac(sha384)", 165362306a36Sopenharmony_ci .hmac_driver_name = "hmac-sha384-caam", 165462306a36Sopenharmony_ci .blocksize = SHA384_BLOCK_SIZE, 165562306a36Sopenharmony_ci .template_ahash = { 165662306a36Sopenharmony_ci .init = ahash_init, 165762306a36Sopenharmony_ci .update = ahash_update, 165862306a36Sopenharmony_ci .final = ahash_final, 165962306a36Sopenharmony_ci .finup = ahash_finup, 166062306a36Sopenharmony_ci .digest = ahash_digest, 166162306a36Sopenharmony_ci .export = ahash_export, 166262306a36Sopenharmony_ci .import = ahash_import, 166362306a36Sopenharmony_ci .setkey = ahash_setkey, 166462306a36Sopenharmony_ci .halg = { 166562306a36Sopenharmony_ci .digestsize = SHA384_DIGEST_SIZE, 166662306a36Sopenharmony_ci .statesize = sizeof(struct caam_export_state), 166762306a36Sopenharmony_ci }, 166862306a36Sopenharmony_ci }, 166962306a36Sopenharmony_ci .alg_type = OP_ALG_ALGSEL_SHA384, 167062306a36Sopenharmony_ci }, { 167162306a36Sopenharmony_ci .name = "sha512", 167262306a36Sopenharmony_ci .driver_name = "sha512-caam", 167362306a36Sopenharmony_ci .hmac_name = "hmac(sha512)", 167462306a36Sopenharmony_ci .hmac_driver_name = "hmac-sha512-caam", 167562306a36Sopenharmony_ci .blocksize = SHA512_BLOCK_SIZE, 167662306a36Sopenharmony_ci .template_ahash = { 167762306a36Sopenharmony_ci .init = ahash_init, 167862306a36Sopenharmony_ci .update = ahash_update, 167962306a36Sopenharmony_ci .final = ahash_final, 168062306a36Sopenharmony_ci .finup = ahash_finup, 168162306a36Sopenharmony_ci .digest = ahash_digest, 168262306a36Sopenharmony_ci .export = ahash_export, 168362306a36Sopenharmony_ci .import = ahash_import, 168462306a36Sopenharmony_ci .setkey = ahash_setkey, 168562306a36Sopenharmony_ci .halg = { 168662306a36Sopenharmony_ci .digestsize = SHA512_DIGEST_SIZE, 168762306a36Sopenharmony_ci .statesize = sizeof(struct caam_export_state), 168862306a36Sopenharmony_ci }, 168962306a36Sopenharmony_ci }, 169062306a36Sopenharmony_ci .alg_type = OP_ALG_ALGSEL_SHA512, 169162306a36Sopenharmony_ci }, { 169262306a36Sopenharmony_ci .name = "md5", 169362306a36Sopenharmony_ci .driver_name = "md5-caam", 169462306a36Sopenharmony_ci .hmac_name = "hmac(md5)", 169562306a36Sopenharmony_ci .hmac_driver_name = "hmac-md5-caam", 169662306a36Sopenharmony_ci .blocksize = MD5_BLOCK_WORDS * 4, 169762306a36Sopenharmony_ci .template_ahash = { 169862306a36Sopenharmony_ci .init = ahash_init, 169962306a36Sopenharmony_ci .update = ahash_update, 170062306a36Sopenharmony_ci .final = ahash_final, 170162306a36Sopenharmony_ci .finup = ahash_finup, 170262306a36Sopenharmony_ci .digest = ahash_digest, 170362306a36Sopenharmony_ci .export = ahash_export, 170462306a36Sopenharmony_ci .import = ahash_import, 170562306a36Sopenharmony_ci .setkey = ahash_setkey, 170662306a36Sopenharmony_ci .halg = { 170762306a36Sopenharmony_ci .digestsize = MD5_DIGEST_SIZE, 170862306a36Sopenharmony_ci .statesize = sizeof(struct caam_export_state), 170962306a36Sopenharmony_ci }, 171062306a36Sopenharmony_ci }, 171162306a36Sopenharmony_ci .alg_type = OP_ALG_ALGSEL_MD5, 171262306a36Sopenharmony_ci }, { 171362306a36Sopenharmony_ci .hmac_name = "xcbc(aes)", 171462306a36Sopenharmony_ci .hmac_driver_name = "xcbc-aes-caam", 171562306a36Sopenharmony_ci .blocksize = AES_BLOCK_SIZE, 171662306a36Sopenharmony_ci .template_ahash = { 171762306a36Sopenharmony_ci .init = ahash_init, 171862306a36Sopenharmony_ci .update = ahash_update, 171962306a36Sopenharmony_ci .final = ahash_final, 172062306a36Sopenharmony_ci .finup = ahash_finup, 172162306a36Sopenharmony_ci .digest = ahash_digest, 172262306a36Sopenharmony_ci .export = ahash_export, 172362306a36Sopenharmony_ci .import = ahash_import, 172462306a36Sopenharmony_ci .setkey = axcbc_setkey, 172562306a36Sopenharmony_ci .halg = { 172662306a36Sopenharmony_ci .digestsize = AES_BLOCK_SIZE, 172762306a36Sopenharmony_ci .statesize = sizeof(struct caam_export_state), 172862306a36Sopenharmony_ci }, 172962306a36Sopenharmony_ci }, 173062306a36Sopenharmony_ci .alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_XCBC_MAC, 173162306a36Sopenharmony_ci }, { 173262306a36Sopenharmony_ci .hmac_name = "cmac(aes)", 173362306a36Sopenharmony_ci .hmac_driver_name = "cmac-aes-caam", 173462306a36Sopenharmony_ci .blocksize = AES_BLOCK_SIZE, 173562306a36Sopenharmony_ci .template_ahash = { 173662306a36Sopenharmony_ci .init = ahash_init, 173762306a36Sopenharmony_ci .update = ahash_update, 173862306a36Sopenharmony_ci .final = ahash_final, 173962306a36Sopenharmony_ci .finup = ahash_finup, 174062306a36Sopenharmony_ci .digest = ahash_digest, 174162306a36Sopenharmony_ci .export = ahash_export, 174262306a36Sopenharmony_ci .import = ahash_import, 174362306a36Sopenharmony_ci .setkey = acmac_setkey, 174462306a36Sopenharmony_ci .halg = { 174562306a36Sopenharmony_ci .digestsize = AES_BLOCK_SIZE, 174662306a36Sopenharmony_ci .statesize = sizeof(struct caam_export_state), 174762306a36Sopenharmony_ci }, 174862306a36Sopenharmony_ci }, 174962306a36Sopenharmony_ci .alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CMAC, 175062306a36Sopenharmony_ci }, 175162306a36Sopenharmony_ci}; 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_cistruct caam_hash_alg { 175462306a36Sopenharmony_ci struct list_head entry; 175562306a36Sopenharmony_ci int alg_type; 175662306a36Sopenharmony_ci struct ahash_engine_alg ahash_alg; 175762306a36Sopenharmony_ci}; 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_cistatic int caam_hash_cra_init(struct crypto_tfm *tfm) 176062306a36Sopenharmony_ci{ 176162306a36Sopenharmony_ci struct crypto_ahash *ahash = __crypto_ahash_cast(tfm); 176262306a36Sopenharmony_ci struct crypto_alg *base = tfm->__crt_alg; 176362306a36Sopenharmony_ci struct hash_alg_common *halg = 176462306a36Sopenharmony_ci container_of(base, struct hash_alg_common, base); 176562306a36Sopenharmony_ci struct ahash_alg *alg = 176662306a36Sopenharmony_ci container_of(halg, struct ahash_alg, halg); 176762306a36Sopenharmony_ci struct caam_hash_alg *caam_hash = 176862306a36Sopenharmony_ci container_of(alg, struct caam_hash_alg, ahash_alg.base); 176962306a36Sopenharmony_ci struct caam_hash_ctx *ctx = crypto_ahash_ctx_dma(ahash); 177062306a36Sopenharmony_ci /* Sizes for MDHA running digests: MD5, SHA1, 224, 256, 384, 512 */ 177162306a36Sopenharmony_ci static const u8 runninglen[] = { HASH_MSG_LEN + MD5_DIGEST_SIZE, 177262306a36Sopenharmony_ci HASH_MSG_LEN + SHA1_DIGEST_SIZE, 177362306a36Sopenharmony_ci HASH_MSG_LEN + 32, 177462306a36Sopenharmony_ci HASH_MSG_LEN + SHA256_DIGEST_SIZE, 177562306a36Sopenharmony_ci HASH_MSG_LEN + 64, 177662306a36Sopenharmony_ci HASH_MSG_LEN + SHA512_DIGEST_SIZE }; 177762306a36Sopenharmony_ci const size_t sh_desc_update_offset = offsetof(struct caam_hash_ctx, 177862306a36Sopenharmony_ci sh_desc_update); 177962306a36Sopenharmony_ci dma_addr_t dma_addr; 178062306a36Sopenharmony_ci struct caam_drv_private *priv; 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci /* 178362306a36Sopenharmony_ci * Get a Job ring from Job Ring driver to ensure in-order 178462306a36Sopenharmony_ci * crypto request processing per tfm 178562306a36Sopenharmony_ci */ 178662306a36Sopenharmony_ci ctx->jrdev = caam_jr_alloc(); 178762306a36Sopenharmony_ci if (IS_ERR(ctx->jrdev)) { 178862306a36Sopenharmony_ci pr_err("Job Ring Device allocation for transform failed\n"); 178962306a36Sopenharmony_ci return PTR_ERR(ctx->jrdev); 179062306a36Sopenharmony_ci } 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci priv = dev_get_drvdata(ctx->jrdev->parent); 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci if (is_xcbc_aes(caam_hash->alg_type)) { 179562306a36Sopenharmony_ci ctx->dir = DMA_TO_DEVICE; 179662306a36Sopenharmony_ci ctx->key_dir = DMA_BIDIRECTIONAL; 179762306a36Sopenharmony_ci ctx->adata.algtype = OP_TYPE_CLASS1_ALG | caam_hash->alg_type; 179862306a36Sopenharmony_ci ctx->ctx_len = 48; 179962306a36Sopenharmony_ci } else if (is_cmac_aes(caam_hash->alg_type)) { 180062306a36Sopenharmony_ci ctx->dir = DMA_TO_DEVICE; 180162306a36Sopenharmony_ci ctx->key_dir = DMA_NONE; 180262306a36Sopenharmony_ci ctx->adata.algtype = OP_TYPE_CLASS1_ALG | caam_hash->alg_type; 180362306a36Sopenharmony_ci ctx->ctx_len = 32; 180462306a36Sopenharmony_ci } else { 180562306a36Sopenharmony_ci if (priv->era >= 6) { 180662306a36Sopenharmony_ci ctx->dir = DMA_BIDIRECTIONAL; 180762306a36Sopenharmony_ci ctx->key_dir = alg->setkey ? DMA_TO_DEVICE : DMA_NONE; 180862306a36Sopenharmony_ci } else { 180962306a36Sopenharmony_ci ctx->dir = DMA_TO_DEVICE; 181062306a36Sopenharmony_ci ctx->key_dir = DMA_NONE; 181162306a36Sopenharmony_ci } 181262306a36Sopenharmony_ci ctx->adata.algtype = OP_TYPE_CLASS2_ALG | caam_hash->alg_type; 181362306a36Sopenharmony_ci ctx->ctx_len = runninglen[(ctx->adata.algtype & 181462306a36Sopenharmony_ci OP_ALG_ALGSEL_SUBMASK) >> 181562306a36Sopenharmony_ci OP_ALG_ALGSEL_SHIFT]; 181662306a36Sopenharmony_ci } 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci if (ctx->key_dir != DMA_NONE) { 181962306a36Sopenharmony_ci ctx->adata.key_dma = dma_map_single_attrs(ctx->jrdev, ctx->key, 182062306a36Sopenharmony_ci ARRAY_SIZE(ctx->key), 182162306a36Sopenharmony_ci ctx->key_dir, 182262306a36Sopenharmony_ci DMA_ATTR_SKIP_CPU_SYNC); 182362306a36Sopenharmony_ci if (dma_mapping_error(ctx->jrdev, ctx->adata.key_dma)) { 182462306a36Sopenharmony_ci dev_err(ctx->jrdev, "unable to map key\n"); 182562306a36Sopenharmony_ci caam_jr_free(ctx->jrdev); 182662306a36Sopenharmony_ci return -ENOMEM; 182762306a36Sopenharmony_ci } 182862306a36Sopenharmony_ci } 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci dma_addr = dma_map_single_attrs(ctx->jrdev, ctx->sh_desc_update, 183162306a36Sopenharmony_ci offsetof(struct caam_hash_ctx, key) - 183262306a36Sopenharmony_ci sh_desc_update_offset, 183362306a36Sopenharmony_ci ctx->dir, DMA_ATTR_SKIP_CPU_SYNC); 183462306a36Sopenharmony_ci if (dma_mapping_error(ctx->jrdev, dma_addr)) { 183562306a36Sopenharmony_ci dev_err(ctx->jrdev, "unable to map shared descriptors\n"); 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci if (ctx->key_dir != DMA_NONE) 183862306a36Sopenharmony_ci dma_unmap_single_attrs(ctx->jrdev, ctx->adata.key_dma, 183962306a36Sopenharmony_ci ARRAY_SIZE(ctx->key), 184062306a36Sopenharmony_ci ctx->key_dir, 184162306a36Sopenharmony_ci DMA_ATTR_SKIP_CPU_SYNC); 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci caam_jr_free(ctx->jrdev); 184462306a36Sopenharmony_ci return -ENOMEM; 184562306a36Sopenharmony_ci } 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_ci ctx->sh_desc_update_dma = dma_addr; 184862306a36Sopenharmony_ci ctx->sh_desc_update_first_dma = dma_addr + 184962306a36Sopenharmony_ci offsetof(struct caam_hash_ctx, 185062306a36Sopenharmony_ci sh_desc_update_first) - 185162306a36Sopenharmony_ci sh_desc_update_offset; 185262306a36Sopenharmony_ci ctx->sh_desc_fin_dma = dma_addr + offsetof(struct caam_hash_ctx, 185362306a36Sopenharmony_ci sh_desc_fin) - 185462306a36Sopenharmony_ci sh_desc_update_offset; 185562306a36Sopenharmony_ci ctx->sh_desc_digest_dma = dma_addr + offsetof(struct caam_hash_ctx, 185662306a36Sopenharmony_ci sh_desc_digest) - 185762306a36Sopenharmony_ci sh_desc_update_offset; 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci crypto_ahash_set_reqsize_dma(ahash, sizeof(struct caam_hash_state)); 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci /* 186262306a36Sopenharmony_ci * For keyed hash algorithms shared descriptors 186362306a36Sopenharmony_ci * will be created later in setkey() callback 186462306a36Sopenharmony_ci */ 186562306a36Sopenharmony_ci return alg->setkey ? 0 : ahash_set_sh_desc(ahash); 186662306a36Sopenharmony_ci} 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_cistatic void caam_hash_cra_exit(struct crypto_tfm *tfm) 186962306a36Sopenharmony_ci{ 187062306a36Sopenharmony_ci struct caam_hash_ctx *ctx = crypto_tfm_ctx_dma(tfm); 187162306a36Sopenharmony_ci 187262306a36Sopenharmony_ci dma_unmap_single_attrs(ctx->jrdev, ctx->sh_desc_update_dma, 187362306a36Sopenharmony_ci offsetof(struct caam_hash_ctx, key) - 187462306a36Sopenharmony_ci offsetof(struct caam_hash_ctx, sh_desc_update), 187562306a36Sopenharmony_ci ctx->dir, DMA_ATTR_SKIP_CPU_SYNC); 187662306a36Sopenharmony_ci if (ctx->key_dir != DMA_NONE) 187762306a36Sopenharmony_ci dma_unmap_single_attrs(ctx->jrdev, ctx->adata.key_dma, 187862306a36Sopenharmony_ci ARRAY_SIZE(ctx->key), ctx->key_dir, 187962306a36Sopenharmony_ci DMA_ATTR_SKIP_CPU_SYNC); 188062306a36Sopenharmony_ci caam_jr_free(ctx->jrdev); 188162306a36Sopenharmony_ci} 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_civoid caam_algapi_hash_exit(void) 188462306a36Sopenharmony_ci{ 188562306a36Sopenharmony_ci struct caam_hash_alg *t_alg, *n; 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci if (!hash_list.next) 188862306a36Sopenharmony_ci return; 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci list_for_each_entry_safe(t_alg, n, &hash_list, entry) { 189162306a36Sopenharmony_ci crypto_engine_unregister_ahash(&t_alg->ahash_alg); 189262306a36Sopenharmony_ci list_del(&t_alg->entry); 189362306a36Sopenharmony_ci kfree(t_alg); 189462306a36Sopenharmony_ci } 189562306a36Sopenharmony_ci} 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_cistatic struct caam_hash_alg * 189862306a36Sopenharmony_cicaam_hash_alloc(struct caam_hash_template *template, 189962306a36Sopenharmony_ci bool keyed) 190062306a36Sopenharmony_ci{ 190162306a36Sopenharmony_ci struct caam_hash_alg *t_alg; 190262306a36Sopenharmony_ci struct ahash_alg *halg; 190362306a36Sopenharmony_ci struct crypto_alg *alg; 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci t_alg = kzalloc(sizeof(*t_alg), GFP_KERNEL); 190662306a36Sopenharmony_ci if (!t_alg) 190762306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci t_alg->ahash_alg.base = template->template_ahash; 191062306a36Sopenharmony_ci halg = &t_alg->ahash_alg.base; 191162306a36Sopenharmony_ci alg = &halg->halg.base; 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci if (keyed) { 191462306a36Sopenharmony_ci snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", 191562306a36Sopenharmony_ci template->hmac_name); 191662306a36Sopenharmony_ci snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", 191762306a36Sopenharmony_ci template->hmac_driver_name); 191862306a36Sopenharmony_ci } else { 191962306a36Sopenharmony_ci snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", 192062306a36Sopenharmony_ci template->name); 192162306a36Sopenharmony_ci snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", 192262306a36Sopenharmony_ci template->driver_name); 192362306a36Sopenharmony_ci halg->setkey = NULL; 192462306a36Sopenharmony_ci } 192562306a36Sopenharmony_ci alg->cra_module = THIS_MODULE; 192662306a36Sopenharmony_ci alg->cra_init = caam_hash_cra_init; 192762306a36Sopenharmony_ci alg->cra_exit = caam_hash_cra_exit; 192862306a36Sopenharmony_ci alg->cra_ctxsize = sizeof(struct caam_hash_ctx) + crypto_dma_padding(); 192962306a36Sopenharmony_ci alg->cra_priority = CAAM_CRA_PRIORITY; 193062306a36Sopenharmony_ci alg->cra_blocksize = template->blocksize; 193162306a36Sopenharmony_ci alg->cra_alignmask = 0; 193262306a36Sopenharmony_ci alg->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY; 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci t_alg->alg_type = template->alg_type; 193562306a36Sopenharmony_ci t_alg->ahash_alg.op.do_one_request = ahash_do_one_req; 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci return t_alg; 193862306a36Sopenharmony_ci} 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_ciint caam_algapi_hash_init(struct device *ctrldev) 194162306a36Sopenharmony_ci{ 194262306a36Sopenharmony_ci int i = 0, err = 0; 194362306a36Sopenharmony_ci struct caam_drv_private *priv = dev_get_drvdata(ctrldev); 194462306a36Sopenharmony_ci unsigned int md_limit = SHA512_DIGEST_SIZE; 194562306a36Sopenharmony_ci u32 md_inst, md_vid; 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci /* 194862306a36Sopenharmony_ci * Register crypto algorithms the device supports. First, identify 194962306a36Sopenharmony_ci * presence and attributes of MD block. 195062306a36Sopenharmony_ci */ 195162306a36Sopenharmony_ci if (priv->era < 10) { 195262306a36Sopenharmony_ci struct caam_perfmon __iomem *perfmon = &priv->jr[0]->perfmon; 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_ci md_vid = (rd_reg32(&perfmon->cha_id_ls) & 195562306a36Sopenharmony_ci CHA_ID_LS_MD_MASK) >> CHA_ID_LS_MD_SHIFT; 195662306a36Sopenharmony_ci md_inst = (rd_reg32(&perfmon->cha_num_ls) & 195762306a36Sopenharmony_ci CHA_ID_LS_MD_MASK) >> CHA_ID_LS_MD_SHIFT; 195862306a36Sopenharmony_ci } else { 195962306a36Sopenharmony_ci u32 mdha = rd_reg32(&priv->jr[0]->vreg.mdha); 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci md_vid = (mdha & CHA_VER_VID_MASK) >> CHA_VER_VID_SHIFT; 196262306a36Sopenharmony_ci md_inst = mdha & CHA_VER_NUM_MASK; 196362306a36Sopenharmony_ci } 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci /* 196662306a36Sopenharmony_ci * Skip registration of any hashing algorithms if MD block 196762306a36Sopenharmony_ci * is not present. 196862306a36Sopenharmony_ci */ 196962306a36Sopenharmony_ci if (!md_inst) 197062306a36Sopenharmony_ci return 0; 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci /* Limit digest size based on LP256 */ 197362306a36Sopenharmony_ci if (md_vid == CHA_VER_VID_MD_LP256) 197462306a36Sopenharmony_ci md_limit = SHA256_DIGEST_SIZE; 197562306a36Sopenharmony_ci 197662306a36Sopenharmony_ci INIT_LIST_HEAD(&hash_list); 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci /* register crypto algorithms the device supports */ 197962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(driver_hash); i++) { 198062306a36Sopenharmony_ci struct caam_hash_alg *t_alg; 198162306a36Sopenharmony_ci struct caam_hash_template *alg = driver_hash + i; 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci /* If MD size is not supported by device, skip registration */ 198462306a36Sopenharmony_ci if (is_mdha(alg->alg_type) && 198562306a36Sopenharmony_ci alg->template_ahash.halg.digestsize > md_limit) 198662306a36Sopenharmony_ci continue; 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_ci /* register hmac version */ 198962306a36Sopenharmony_ci t_alg = caam_hash_alloc(alg, true); 199062306a36Sopenharmony_ci if (IS_ERR(t_alg)) { 199162306a36Sopenharmony_ci err = PTR_ERR(t_alg); 199262306a36Sopenharmony_ci pr_warn("%s alg allocation failed\n", 199362306a36Sopenharmony_ci alg->hmac_driver_name); 199462306a36Sopenharmony_ci continue; 199562306a36Sopenharmony_ci } 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci err = crypto_engine_register_ahash(&t_alg->ahash_alg); 199862306a36Sopenharmony_ci if (err) { 199962306a36Sopenharmony_ci pr_warn("%s alg registration failed: %d\n", 200062306a36Sopenharmony_ci t_alg->ahash_alg.base.halg.base.cra_driver_name, 200162306a36Sopenharmony_ci err); 200262306a36Sopenharmony_ci kfree(t_alg); 200362306a36Sopenharmony_ci } else 200462306a36Sopenharmony_ci list_add_tail(&t_alg->entry, &hash_list); 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_ci if ((alg->alg_type & OP_ALG_ALGSEL_MASK) == OP_ALG_ALGSEL_AES) 200762306a36Sopenharmony_ci continue; 200862306a36Sopenharmony_ci 200962306a36Sopenharmony_ci /* register unkeyed version */ 201062306a36Sopenharmony_ci t_alg = caam_hash_alloc(alg, false); 201162306a36Sopenharmony_ci if (IS_ERR(t_alg)) { 201262306a36Sopenharmony_ci err = PTR_ERR(t_alg); 201362306a36Sopenharmony_ci pr_warn("%s alg allocation failed\n", alg->driver_name); 201462306a36Sopenharmony_ci continue; 201562306a36Sopenharmony_ci } 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_ci err = crypto_engine_register_ahash(&t_alg->ahash_alg); 201862306a36Sopenharmony_ci if (err) { 201962306a36Sopenharmony_ci pr_warn("%s alg registration failed: %d\n", 202062306a36Sopenharmony_ci t_alg->ahash_alg.base.halg.base.cra_driver_name, 202162306a36Sopenharmony_ci err); 202262306a36Sopenharmony_ci kfree(t_alg); 202362306a36Sopenharmony_ci } else 202462306a36Sopenharmony_ci list_add_tail(&t_alg->entry, &hash_list); 202562306a36Sopenharmony_ci } 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci return err; 202862306a36Sopenharmony_ci} 2029