162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * sun8i-ce-hash.c - hardware cryptographic offloader for 462306a36Sopenharmony_ci * Allwinner H3/A64/H5/H2+/H6/R40 SoC 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2015-2020 Corentin Labbe <clabbe@baylibre.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * This file add support for MD5 and SHA1/SHA224/SHA256/SHA384/SHA512. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * You could find the datasheet in Documentation/arch/arm/sunxi.rst 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <crypto/internal/hash.h> 1462306a36Sopenharmony_ci#include <crypto/md5.h> 1562306a36Sopenharmony_ci#include <crypto/sha1.h> 1662306a36Sopenharmony_ci#include <crypto/sha2.h> 1762306a36Sopenharmony_ci#include <linux/bottom_half.h> 1862306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1962306a36Sopenharmony_ci#include <linux/kernel.h> 2062306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2162306a36Sopenharmony_ci#include <linux/scatterlist.h> 2262306a36Sopenharmony_ci#include <linux/slab.h> 2362306a36Sopenharmony_ci#include <linux/string.h> 2462306a36Sopenharmony_ci#include "sun8i-ce.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ciint sun8i_ce_hash_init_tfm(struct crypto_ahash *tfm) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci struct sun8i_ce_hash_tfm_ctx *op = crypto_ahash_ctx(tfm); 2962306a36Sopenharmony_ci struct ahash_alg *alg = crypto_ahash_alg(tfm); 3062306a36Sopenharmony_ci struct sun8i_ce_alg_template *algt; 3162306a36Sopenharmony_ci int err; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash.base); 3462306a36Sopenharmony_ci op->ce = algt->ce; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci /* FALLBACK */ 3762306a36Sopenharmony_ci op->fallback_tfm = crypto_alloc_ahash(crypto_ahash_alg_name(tfm), 0, 3862306a36Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK); 3962306a36Sopenharmony_ci if (IS_ERR(op->fallback_tfm)) { 4062306a36Sopenharmony_ci dev_err(algt->ce->dev, "Fallback driver could no be loaded\n"); 4162306a36Sopenharmony_ci return PTR_ERR(op->fallback_tfm); 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci crypto_ahash_set_statesize(tfm, 4562306a36Sopenharmony_ci crypto_ahash_statesize(op->fallback_tfm)); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci crypto_ahash_set_reqsize(tfm, 4862306a36Sopenharmony_ci sizeof(struct sun8i_ce_hash_reqctx) + 4962306a36Sopenharmony_ci crypto_ahash_reqsize(op->fallback_tfm)); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci memcpy(algt->fbname, crypto_ahash_driver_name(op->fallback_tfm), 5262306a36Sopenharmony_ci CRYPTO_MAX_ALG_NAME); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci err = pm_runtime_get_sync(op->ce->dev); 5562306a36Sopenharmony_ci if (err < 0) 5662306a36Sopenharmony_ci goto error_pm; 5762306a36Sopenharmony_ci return 0; 5862306a36Sopenharmony_cierror_pm: 5962306a36Sopenharmony_ci pm_runtime_put_noidle(op->ce->dev); 6062306a36Sopenharmony_ci crypto_free_ahash(op->fallback_tfm); 6162306a36Sopenharmony_ci return err; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_civoid sun8i_ce_hash_exit_tfm(struct crypto_ahash *tfm) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci crypto_free_ahash(tfmctx->fallback_tfm); 6962306a36Sopenharmony_ci pm_runtime_put_sync_suspend(tfmctx->ce->dev); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ciint sun8i_ce_hash_init(struct ahash_request *areq) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq); 7562306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); 7662306a36Sopenharmony_ci struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci memset(rctx, 0, sizeof(struct sun8i_ce_hash_reqctx)); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm); 8162306a36Sopenharmony_ci rctx->fallback_req.base.flags = areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci return crypto_ahash_init(&rctx->fallback_req); 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ciint sun8i_ce_hash_export(struct ahash_request *areq, void *out) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq); 8962306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); 9062306a36Sopenharmony_ci struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm); 9362306a36Sopenharmony_ci rctx->fallback_req.base.flags = areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci return crypto_ahash_export(&rctx->fallback_req, out); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ciint sun8i_ce_hash_import(struct ahash_request *areq, const void *in) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq); 10162306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); 10262306a36Sopenharmony_ci struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm); 10562306a36Sopenharmony_ci rctx->fallback_req.base.flags = areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci return crypto_ahash_import(&rctx->fallback_req, in); 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ciint sun8i_ce_hash_final(struct ahash_request *areq) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq); 11362306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); 11462306a36Sopenharmony_ci struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm); 11762306a36Sopenharmony_ci rctx->fallback_req.base.flags = areq->base.flags & 11862306a36Sopenharmony_ci CRYPTO_TFM_REQ_MAY_SLEEP; 11962306a36Sopenharmony_ci rctx->fallback_req.result = areq->result; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG)) { 12262306a36Sopenharmony_ci struct sun8i_ce_alg_template *algt __maybe_unused; 12362306a36Sopenharmony_ci struct ahash_alg *alg = crypto_ahash_alg(tfm); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci algt = container_of(alg, struct sun8i_ce_alg_template, 12662306a36Sopenharmony_ci alg.hash.base); 12762306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG 12862306a36Sopenharmony_ci algt->stat_fb++; 12962306a36Sopenharmony_ci#endif 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci return crypto_ahash_final(&rctx->fallback_req); 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ciint sun8i_ce_hash_update(struct ahash_request *areq) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq); 13862306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); 13962306a36Sopenharmony_ci struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm); 14262306a36Sopenharmony_ci rctx->fallback_req.base.flags = areq->base.flags & 14362306a36Sopenharmony_ci CRYPTO_TFM_REQ_MAY_SLEEP; 14462306a36Sopenharmony_ci rctx->fallback_req.nbytes = areq->nbytes; 14562306a36Sopenharmony_ci rctx->fallback_req.src = areq->src; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci return crypto_ahash_update(&rctx->fallback_req); 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ciint sun8i_ce_hash_finup(struct ahash_request *areq) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq); 15362306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); 15462306a36Sopenharmony_ci struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm); 15762306a36Sopenharmony_ci rctx->fallback_req.base.flags = areq->base.flags & 15862306a36Sopenharmony_ci CRYPTO_TFM_REQ_MAY_SLEEP; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci rctx->fallback_req.nbytes = areq->nbytes; 16162306a36Sopenharmony_ci rctx->fallback_req.src = areq->src; 16262306a36Sopenharmony_ci rctx->fallback_req.result = areq->result; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG)) { 16562306a36Sopenharmony_ci struct sun8i_ce_alg_template *algt __maybe_unused; 16662306a36Sopenharmony_ci struct ahash_alg *alg = crypto_ahash_alg(tfm); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci algt = container_of(alg, struct sun8i_ce_alg_template, 16962306a36Sopenharmony_ci alg.hash.base); 17062306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG 17162306a36Sopenharmony_ci algt->stat_fb++; 17262306a36Sopenharmony_ci#endif 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci return crypto_ahash_finup(&rctx->fallback_req); 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic int sun8i_ce_hash_digest_fb(struct ahash_request *areq) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq); 18162306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); 18262306a36Sopenharmony_ci struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm); 18562306a36Sopenharmony_ci rctx->fallback_req.base.flags = areq->base.flags & 18662306a36Sopenharmony_ci CRYPTO_TFM_REQ_MAY_SLEEP; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci rctx->fallback_req.nbytes = areq->nbytes; 18962306a36Sopenharmony_ci rctx->fallback_req.src = areq->src; 19062306a36Sopenharmony_ci rctx->fallback_req.result = areq->result; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG)) { 19362306a36Sopenharmony_ci struct sun8i_ce_alg_template *algt __maybe_unused; 19462306a36Sopenharmony_ci struct ahash_alg *alg = crypto_ahash_alg(tfm); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci algt = container_of(alg, struct sun8i_ce_alg_template, 19762306a36Sopenharmony_ci alg.hash.base); 19862306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG 19962306a36Sopenharmony_ci algt->stat_fb++; 20062306a36Sopenharmony_ci#endif 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci return crypto_ahash_digest(&rctx->fallback_req); 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic bool sun8i_ce_hash_need_fallback(struct ahash_request *areq) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); 20962306a36Sopenharmony_ci struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg); 21062306a36Sopenharmony_ci struct sun8i_ce_alg_template *algt; 21162306a36Sopenharmony_ci struct scatterlist *sg; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash.base); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (areq->nbytes == 0) { 21662306a36Sopenharmony_ci algt->stat_fb_len0++; 21762306a36Sopenharmony_ci return true; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci /* we need to reserve one SG for padding one */ 22062306a36Sopenharmony_ci if (sg_nents_for_len(areq->src, areq->nbytes) > MAX_SG - 1) { 22162306a36Sopenharmony_ci algt->stat_fb_maxsg++; 22262306a36Sopenharmony_ci return true; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci sg = areq->src; 22562306a36Sopenharmony_ci while (sg) { 22662306a36Sopenharmony_ci if (sg->length % 4) { 22762306a36Sopenharmony_ci algt->stat_fb_srclen++; 22862306a36Sopenharmony_ci return true; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci if (!IS_ALIGNED(sg->offset, sizeof(u32))) { 23162306a36Sopenharmony_ci algt->stat_fb_srcali++; 23262306a36Sopenharmony_ci return true; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci sg = sg_next(sg); 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci return false; 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ciint sun8i_ce_hash_digest(struct ahash_request *areq) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); 24262306a36Sopenharmony_ci struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg); 24362306a36Sopenharmony_ci struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq); 24462306a36Sopenharmony_ci struct sun8i_ce_alg_template *algt; 24562306a36Sopenharmony_ci struct sun8i_ce_dev *ce; 24662306a36Sopenharmony_ci struct crypto_engine *engine; 24762306a36Sopenharmony_ci struct scatterlist *sg; 24862306a36Sopenharmony_ci int nr_sgs, e, i; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (sun8i_ce_hash_need_fallback(areq)) 25162306a36Sopenharmony_ci return sun8i_ce_hash_digest_fb(areq); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci nr_sgs = sg_nents_for_len(areq->src, areq->nbytes); 25462306a36Sopenharmony_ci if (nr_sgs > MAX_SG - 1) 25562306a36Sopenharmony_ci return sun8i_ce_hash_digest_fb(areq); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci for_each_sg(areq->src, sg, nr_sgs, i) { 25862306a36Sopenharmony_ci if (sg->length % 4 || !IS_ALIGNED(sg->offset, sizeof(u32))) 25962306a36Sopenharmony_ci return sun8i_ce_hash_digest_fb(areq); 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash.base); 26362306a36Sopenharmony_ci ce = algt->ce; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci e = sun8i_ce_get_engine_number(ce); 26662306a36Sopenharmony_ci rctx->flow = e; 26762306a36Sopenharmony_ci engine = ce->chanlist[e].engine; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci return crypto_transfer_hash_request_to_engine(engine, areq); 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic u64 hash_pad(__le32 *buf, unsigned int bufsize, u64 padi, u64 byte_count, bool le, int bs) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci u64 fill, min_fill, j, k; 27562306a36Sopenharmony_ci __be64 *bebits; 27662306a36Sopenharmony_ci __le64 *lebits; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci j = padi; 27962306a36Sopenharmony_ci buf[j++] = cpu_to_le32(0x80); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci if (bs == 64) { 28262306a36Sopenharmony_ci fill = 64 - (byte_count % 64); 28362306a36Sopenharmony_ci min_fill = 2 * sizeof(u32) + sizeof(u32); 28462306a36Sopenharmony_ci } else { 28562306a36Sopenharmony_ci fill = 128 - (byte_count % 128); 28662306a36Sopenharmony_ci min_fill = 4 * sizeof(u32) + sizeof(u32); 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (fill < min_fill) 29062306a36Sopenharmony_ci fill += bs; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci k = j; 29362306a36Sopenharmony_ci j += (fill - min_fill) / sizeof(u32); 29462306a36Sopenharmony_ci if (j * 4 > bufsize) { 29562306a36Sopenharmony_ci pr_err("%s OVERFLOW %llu\n", __func__, j); 29662306a36Sopenharmony_ci return 0; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci for (; k < j; k++) 29962306a36Sopenharmony_ci buf[k] = 0; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (le) { 30262306a36Sopenharmony_ci /* MD5 */ 30362306a36Sopenharmony_ci lebits = (__le64 *)&buf[j]; 30462306a36Sopenharmony_ci *lebits = cpu_to_le64(byte_count << 3); 30562306a36Sopenharmony_ci j += 2; 30662306a36Sopenharmony_ci } else { 30762306a36Sopenharmony_ci if (bs == 64) { 30862306a36Sopenharmony_ci /* sha1 sha224 sha256 */ 30962306a36Sopenharmony_ci bebits = (__be64 *)&buf[j]; 31062306a36Sopenharmony_ci *bebits = cpu_to_be64(byte_count << 3); 31162306a36Sopenharmony_ci j += 2; 31262306a36Sopenharmony_ci } else { 31362306a36Sopenharmony_ci /* sha384 sha512*/ 31462306a36Sopenharmony_ci bebits = (__be64 *)&buf[j]; 31562306a36Sopenharmony_ci *bebits = cpu_to_be64(byte_count >> 61); 31662306a36Sopenharmony_ci j += 2; 31762306a36Sopenharmony_ci bebits = (__be64 *)&buf[j]; 31862306a36Sopenharmony_ci *bebits = cpu_to_be64(byte_count << 3); 31962306a36Sopenharmony_ci j += 2; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci if (j * 4 > bufsize) { 32362306a36Sopenharmony_ci pr_err("%s OVERFLOW %llu\n", __func__, j); 32462306a36Sopenharmony_ci return 0; 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci return j; 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ciint sun8i_ce_hash_run(struct crypto_engine *engine, void *breq) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci struct ahash_request *areq = container_of(breq, struct ahash_request, base); 33362306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); 33462306a36Sopenharmony_ci struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg); 33562306a36Sopenharmony_ci struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq); 33662306a36Sopenharmony_ci struct sun8i_ce_alg_template *algt; 33762306a36Sopenharmony_ci struct sun8i_ce_dev *ce; 33862306a36Sopenharmony_ci struct sun8i_ce_flow *chan; 33962306a36Sopenharmony_ci struct ce_task *cet; 34062306a36Sopenharmony_ci struct scatterlist *sg; 34162306a36Sopenharmony_ci int nr_sgs, flow, err; 34262306a36Sopenharmony_ci unsigned int len; 34362306a36Sopenharmony_ci u32 common; 34462306a36Sopenharmony_ci u64 byte_count; 34562306a36Sopenharmony_ci __le32 *bf; 34662306a36Sopenharmony_ci void *buf = NULL; 34762306a36Sopenharmony_ci int j, i, todo; 34862306a36Sopenharmony_ci void *result = NULL; 34962306a36Sopenharmony_ci u64 bs; 35062306a36Sopenharmony_ci int digestsize; 35162306a36Sopenharmony_ci dma_addr_t addr_res, addr_pad; 35262306a36Sopenharmony_ci int ns = sg_nents_for_len(areq->src, areq->nbytes); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash.base); 35562306a36Sopenharmony_ci ce = algt->ce; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci bs = algt->alg.hash.base.halg.base.cra_blocksize; 35862306a36Sopenharmony_ci digestsize = algt->alg.hash.base.halg.digestsize; 35962306a36Sopenharmony_ci if (digestsize == SHA224_DIGEST_SIZE) 36062306a36Sopenharmony_ci digestsize = SHA256_DIGEST_SIZE; 36162306a36Sopenharmony_ci if (digestsize == SHA384_DIGEST_SIZE) 36262306a36Sopenharmony_ci digestsize = SHA512_DIGEST_SIZE; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci /* the padding could be up to two block. */ 36562306a36Sopenharmony_ci buf = kzalloc(bs * 2, GFP_KERNEL | GFP_DMA); 36662306a36Sopenharmony_ci if (!buf) { 36762306a36Sopenharmony_ci err = -ENOMEM; 36862306a36Sopenharmony_ci goto theend; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci bf = (__le32 *)buf; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci result = kzalloc(digestsize, GFP_KERNEL | GFP_DMA); 37362306a36Sopenharmony_ci if (!result) { 37462306a36Sopenharmony_ci err = -ENOMEM; 37562306a36Sopenharmony_ci goto theend; 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci flow = rctx->flow; 37962306a36Sopenharmony_ci chan = &ce->chanlist[flow]; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG 38262306a36Sopenharmony_ci algt->stat_req++; 38362306a36Sopenharmony_ci#endif 38462306a36Sopenharmony_ci dev_dbg(ce->dev, "%s %s len=%d\n", __func__, crypto_tfm_alg_name(areq->base.tfm), areq->nbytes); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci cet = chan->tl; 38762306a36Sopenharmony_ci memset(cet, 0, sizeof(struct ce_task)); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci cet->t_id = cpu_to_le32(flow); 39062306a36Sopenharmony_ci common = ce->variant->alg_hash[algt->ce_algo_id]; 39162306a36Sopenharmony_ci common |= CE_COMM_INT; 39262306a36Sopenharmony_ci cet->t_common_ctl = cpu_to_le32(common); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci cet->t_sym_ctl = 0; 39562306a36Sopenharmony_ci cet->t_asym_ctl = 0; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci nr_sgs = dma_map_sg(ce->dev, areq->src, ns, DMA_TO_DEVICE); 39862306a36Sopenharmony_ci if (nr_sgs <= 0 || nr_sgs > MAX_SG) { 39962306a36Sopenharmony_ci dev_err(ce->dev, "Invalid sg number %d\n", nr_sgs); 40062306a36Sopenharmony_ci err = -EINVAL; 40162306a36Sopenharmony_ci goto theend; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci len = areq->nbytes; 40562306a36Sopenharmony_ci for_each_sg(areq->src, sg, nr_sgs, i) { 40662306a36Sopenharmony_ci cet->t_src[i].addr = cpu_to_le32(sg_dma_address(sg)); 40762306a36Sopenharmony_ci todo = min(len, sg_dma_len(sg)); 40862306a36Sopenharmony_ci cet->t_src[i].len = cpu_to_le32(todo / 4); 40962306a36Sopenharmony_ci len -= todo; 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci if (len > 0) { 41262306a36Sopenharmony_ci dev_err(ce->dev, "remaining len %d\n", len); 41362306a36Sopenharmony_ci err = -EINVAL; 41462306a36Sopenharmony_ci goto theend; 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci addr_res = dma_map_single(ce->dev, result, digestsize, DMA_FROM_DEVICE); 41762306a36Sopenharmony_ci cet->t_dst[0].addr = cpu_to_le32(addr_res); 41862306a36Sopenharmony_ci cet->t_dst[0].len = cpu_to_le32(digestsize / 4); 41962306a36Sopenharmony_ci if (dma_mapping_error(ce->dev, addr_res)) { 42062306a36Sopenharmony_ci dev_err(ce->dev, "DMA map dest\n"); 42162306a36Sopenharmony_ci err = -EINVAL; 42262306a36Sopenharmony_ci goto theend; 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci byte_count = areq->nbytes; 42662306a36Sopenharmony_ci j = 0; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci switch (algt->ce_algo_id) { 42962306a36Sopenharmony_ci case CE_ID_HASH_MD5: 43062306a36Sopenharmony_ci j = hash_pad(bf, 2 * bs, j, byte_count, true, bs); 43162306a36Sopenharmony_ci break; 43262306a36Sopenharmony_ci case CE_ID_HASH_SHA1: 43362306a36Sopenharmony_ci case CE_ID_HASH_SHA224: 43462306a36Sopenharmony_ci case CE_ID_HASH_SHA256: 43562306a36Sopenharmony_ci j = hash_pad(bf, 2 * bs, j, byte_count, false, bs); 43662306a36Sopenharmony_ci break; 43762306a36Sopenharmony_ci case CE_ID_HASH_SHA384: 43862306a36Sopenharmony_ci case CE_ID_HASH_SHA512: 43962306a36Sopenharmony_ci j = hash_pad(bf, 2 * bs, j, byte_count, false, bs); 44062306a36Sopenharmony_ci break; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci if (!j) { 44362306a36Sopenharmony_ci err = -EINVAL; 44462306a36Sopenharmony_ci goto theend; 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci addr_pad = dma_map_single(ce->dev, buf, j * 4, DMA_TO_DEVICE); 44862306a36Sopenharmony_ci cet->t_src[i].addr = cpu_to_le32(addr_pad); 44962306a36Sopenharmony_ci cet->t_src[i].len = cpu_to_le32(j); 45062306a36Sopenharmony_ci if (dma_mapping_error(ce->dev, addr_pad)) { 45162306a36Sopenharmony_ci dev_err(ce->dev, "DMA error on padding SG\n"); 45262306a36Sopenharmony_ci err = -EINVAL; 45362306a36Sopenharmony_ci goto theend; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci if (ce->variant->hash_t_dlen_in_bits) 45762306a36Sopenharmony_ci cet->t_dlen = cpu_to_le32((areq->nbytes + j * 4) * 8); 45862306a36Sopenharmony_ci else 45962306a36Sopenharmony_ci cet->t_dlen = cpu_to_le32(areq->nbytes / 4 + j); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci chan->timeout = areq->nbytes; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci err = sun8i_ce_run_task(ce, flow, crypto_ahash_alg_name(tfm)); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci dma_unmap_single(ce->dev, addr_pad, j * 4, DMA_TO_DEVICE); 46662306a36Sopenharmony_ci dma_unmap_sg(ce->dev, areq->src, ns, DMA_TO_DEVICE); 46762306a36Sopenharmony_ci dma_unmap_single(ce->dev, addr_res, digestsize, DMA_FROM_DEVICE); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci memcpy(areq->result, result, algt->alg.hash.base.halg.digestsize); 47162306a36Sopenharmony_citheend: 47262306a36Sopenharmony_ci kfree(buf); 47362306a36Sopenharmony_ci kfree(result); 47462306a36Sopenharmony_ci local_bh_disable(); 47562306a36Sopenharmony_ci crypto_finalize_hash_request(engine, breq, err); 47662306a36Sopenharmony_ci local_bh_enable(); 47762306a36Sopenharmony_ci return 0; 47862306a36Sopenharmony_ci} 479