Path: blob/master/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c
29537 views
// SPDX-License-Identifier: GPL-2.01/*2* sun8i-ce-hash.c - hardware cryptographic offloader for3* Allwinner H3/A64/H5/H2+/H6/R40 SoC4*5* Copyright (C) 2015-2020 Corentin Labbe <[email protected]>6*7* This file add support for MD5 and SHA1/SHA224/SHA256/SHA384/SHA512.8*9* You could find the datasheet in Documentation/arch/arm/sunxi.rst10*/1112#include <crypto/internal/hash.h>13#include <crypto/md5.h>14#include <crypto/sha1.h>15#include <crypto/sha2.h>16#include <linux/bottom_half.h>17#include <linux/dma-mapping.h>18#include <linux/kernel.h>19#include <linux/pm_runtime.h>20#include <linux/scatterlist.h>21#include <linux/slab.h>22#include <linux/string.h>23#include "sun8i-ce.h"2425static void sun8i_ce_hash_stat_fb_inc(struct crypto_ahash *tfm)26{27if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG)) {28struct sun8i_ce_alg_template *algt;29struct ahash_alg *alg = crypto_ahash_alg(tfm);3031algt = container_of(alg, struct sun8i_ce_alg_template,32alg.hash.base);33algt->stat_fb++;34}35}3637int sun8i_ce_hash_init_tfm(struct crypto_ahash *tfm)38{39struct sun8i_ce_hash_tfm_ctx *op = crypto_ahash_ctx(tfm);40struct ahash_alg *alg = crypto_ahash_alg(tfm);41struct sun8i_ce_alg_template *algt;42int err;4344algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash.base);45op->ce = algt->ce;4647/* FALLBACK */48op->fallback_tfm = crypto_alloc_ahash(crypto_ahash_alg_name(tfm), 0,49CRYPTO_ALG_NEED_FALLBACK);50if (IS_ERR(op->fallback_tfm)) {51dev_err(algt->ce->dev, "Fallback driver could no be loaded\n");52return PTR_ERR(op->fallback_tfm);53}5455crypto_ahash_set_statesize(tfm,56crypto_ahash_statesize(op->fallback_tfm));5758crypto_ahash_set_reqsize(tfm,59sizeof(struct sun8i_ce_hash_reqctx) +60crypto_ahash_reqsize(op->fallback_tfm) +61CRYPTO_DMA_PADDING);6263if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG))64memcpy(algt->fbname,65crypto_ahash_driver_name(op->fallback_tfm),66CRYPTO_MAX_ALG_NAME);6768err = pm_runtime_resume_and_get(op->ce->dev);69if (err < 0)70goto error_pm;71return 0;72error_pm:73crypto_free_ahash(op->fallback_tfm);74return err;75}7677void sun8i_ce_hash_exit_tfm(struct crypto_ahash *tfm)78{79struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);8081crypto_free_ahash(tfmctx->fallback_tfm);82pm_runtime_put_sync_suspend(tfmctx->ce->dev);83}8485int sun8i_ce_hash_init(struct ahash_request *areq)86{87struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx_dma(areq);88struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);89struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);9091memset(rctx, 0, sizeof(struct sun8i_ce_hash_reqctx));9293ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);94ahash_request_set_callback(&rctx->fallback_req,95areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP,96areq->base.complete, areq->base.data);9798return crypto_ahash_init(&rctx->fallback_req);99}100101int sun8i_ce_hash_export(struct ahash_request *areq, void *out)102{103struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx_dma(areq);104struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);105struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);106107ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);108ahash_request_set_callback(&rctx->fallback_req,109areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP,110areq->base.complete, areq->base.data);111112return crypto_ahash_export(&rctx->fallback_req, out);113}114115int sun8i_ce_hash_import(struct ahash_request *areq, const void *in)116{117struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx_dma(areq);118struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);119struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);120121ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);122ahash_request_set_callback(&rctx->fallback_req,123areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP,124areq->base.complete, areq->base.data);125126return crypto_ahash_import(&rctx->fallback_req, in);127}128129int sun8i_ce_hash_final(struct ahash_request *areq)130{131struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx_dma(areq);132struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);133struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);134135sun8i_ce_hash_stat_fb_inc(tfm);136137ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);138ahash_request_set_callback(&rctx->fallback_req,139areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP,140areq->base.complete, areq->base.data);141ahash_request_set_crypt(&rctx->fallback_req, NULL, areq->result, 0);142143return crypto_ahash_final(&rctx->fallback_req);144}145146int sun8i_ce_hash_update(struct ahash_request *areq)147{148struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx_dma(areq);149struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);150struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);151152ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);153ahash_request_set_callback(&rctx->fallback_req,154areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP,155areq->base.complete, areq->base.data);156ahash_request_set_crypt(&rctx->fallback_req, areq->src, NULL, areq->nbytes);157158return crypto_ahash_update(&rctx->fallback_req);159}160161int sun8i_ce_hash_finup(struct ahash_request *areq)162{163struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx_dma(areq);164struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);165struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);166167sun8i_ce_hash_stat_fb_inc(tfm);168169ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);170ahash_request_set_callback(&rctx->fallback_req,171areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP,172areq->base.complete, areq->base.data);173ahash_request_set_crypt(&rctx->fallback_req, areq->src, areq->result,174areq->nbytes);175176return crypto_ahash_finup(&rctx->fallback_req);177}178179static int sun8i_ce_hash_digest_fb(struct ahash_request *areq)180{181struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx_dma(areq);182struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);183struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);184185sun8i_ce_hash_stat_fb_inc(tfm);186187ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);188ahash_request_set_callback(&rctx->fallback_req,189areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP,190areq->base.complete, areq->base.data);191ahash_request_set_crypt(&rctx->fallback_req, areq->src, areq->result,192areq->nbytes);193194return crypto_ahash_digest(&rctx->fallback_req);195}196197static bool sun8i_ce_hash_need_fallback(struct ahash_request *areq)198{199struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);200struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);201struct sun8i_ce_alg_template *algt;202struct scatterlist *sg;203204algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash.base);205206if (areq->nbytes == 0) {207if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG))208algt->stat_fb_len0++;209210return true;211}212/* we need to reserve one SG for padding one */213if (sg_nents_for_len(areq->src, areq->nbytes) > MAX_SG - 1) {214if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG))215algt->stat_fb_maxsg++;216217return true;218}219sg = areq->src;220while (sg) {221if (sg->length % 4) {222if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG))223algt->stat_fb_srclen++;224225return true;226}227if (!IS_ALIGNED(sg->offset, sizeof(u32))) {228if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG))229algt->stat_fb_srcali++;230231return true;232}233sg = sg_next(sg);234}235return false;236}237238int sun8i_ce_hash_digest(struct ahash_request *areq)239{240struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);241struct sun8i_ce_hash_tfm_ctx *ctx = crypto_ahash_ctx(tfm);242struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx_dma(areq);243struct sun8i_ce_dev *ce = ctx->ce;244struct crypto_engine *engine;245int e;246247if (sun8i_ce_hash_need_fallback(areq))248return sun8i_ce_hash_digest_fb(areq);249250e = sun8i_ce_get_engine_number(ce);251rctx->flow = e;252engine = ce->chanlist[e].engine;253254return crypto_transfer_hash_request_to_engine(engine, areq);255}256257static u64 hash_pad(__le32 *buf, unsigned int bufsize, u64 padi, u64 byte_count, bool le, int bs)258{259u64 fill, min_fill, j, k;260__be64 *bebits;261__le64 *lebits;262263j = padi;264buf[j++] = cpu_to_le32(0x80);265266if (bs == 64) {267fill = 64 - (byte_count % 64);268min_fill = 2 * sizeof(u32) + sizeof(u32);269} else {270fill = 128 - (byte_count % 128);271min_fill = 4 * sizeof(u32) + sizeof(u32);272}273274if (fill < min_fill)275fill += bs;276277k = j;278j += (fill - min_fill) / sizeof(u32);279if (j * 4 > bufsize) {280pr_err("%s OVERFLOW %llu\n", __func__, j);281return 0;282}283for (; k < j; k++)284buf[k] = 0;285286if (le) {287/* MD5 */288lebits = (__le64 *)&buf[j];289*lebits = cpu_to_le64(byte_count << 3);290j += 2;291} else {292if (bs == 64) {293/* sha1 sha224 sha256 */294bebits = (__be64 *)&buf[j];295*bebits = cpu_to_be64(byte_count << 3);296j += 2;297} else {298/* sha384 sha512*/299bebits = (__be64 *)&buf[j];300*bebits = cpu_to_be64(byte_count >> 61);301j += 2;302bebits = (__be64 *)&buf[j];303*bebits = cpu_to_be64(byte_count << 3);304j += 2;305}306}307if (j * 4 > bufsize) {308pr_err("%s OVERFLOW %llu\n", __func__, j);309return 0;310}311312return j;313}314315static int sun8i_ce_hash_prepare(struct ahash_request *areq, struct ce_task *cet)316{317struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);318struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);319struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx_dma(areq);320struct sun8i_ce_alg_template *algt;321struct sun8i_ce_dev *ce;322struct scatterlist *sg;323int nr_sgs, err;324unsigned int len;325u32 common;326u64 byte_count;327__le32 *bf;328int j, i, todo;329u64 bs;330int digestsize;331332algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash.base);333ce = algt->ce;334335bs = crypto_ahash_blocksize(tfm);336digestsize = crypto_ahash_digestsize(tfm);337if (digestsize == SHA224_DIGEST_SIZE)338digestsize = SHA256_DIGEST_SIZE;339if (digestsize == SHA384_DIGEST_SIZE)340digestsize = SHA512_DIGEST_SIZE;341342bf = (__le32 *)rctx->pad;343344if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG))345algt->stat_req++;346347dev_dbg(ce->dev, "%s %s len=%d\n", __func__, crypto_tfm_alg_name(areq->base.tfm), areq->nbytes);348349memset(cet, 0, sizeof(struct ce_task));350351cet->t_id = cpu_to_le32(rctx->flow);352common = ce->variant->alg_hash[algt->ce_algo_id];353common |= CE_COMM_INT;354cet->t_common_ctl = cpu_to_le32(common);355356cet->t_sym_ctl = 0;357cet->t_asym_ctl = 0;358359rctx->nr_sgs = sg_nents_for_len(areq->src, areq->nbytes);360nr_sgs = dma_map_sg(ce->dev, areq->src, rctx->nr_sgs, DMA_TO_DEVICE);361if (nr_sgs <= 0 || nr_sgs > MAX_SG) {362dev_err(ce->dev, "Invalid sg number %d\n", nr_sgs);363err = -EINVAL;364goto err_out;365}366367len = areq->nbytes;368for_each_sg(areq->src, sg, nr_sgs, i) {369cet->t_src[i].addr = desc_addr_val_le32(ce, sg_dma_address(sg));370todo = min(len, sg_dma_len(sg));371cet->t_src[i].len = cpu_to_le32(todo / 4);372len -= todo;373}374if (len > 0) {375dev_err(ce->dev, "remaining len %d\n", len);376err = -EINVAL;377goto err_unmap_src;378}379380rctx->result_len = digestsize;381rctx->addr_res = dma_map_single(ce->dev, rctx->result, rctx->result_len,382DMA_FROM_DEVICE);383cet->t_dst[0].addr = desc_addr_val_le32(ce, rctx->addr_res);384cet->t_dst[0].len = cpu_to_le32(rctx->result_len / 4);385if (dma_mapping_error(ce->dev, rctx->addr_res)) {386dev_err(ce->dev, "DMA map dest\n");387err = -EINVAL;388goto err_unmap_src;389}390391byte_count = areq->nbytes;392j = 0;393394switch (algt->ce_algo_id) {395case CE_ID_HASH_MD5:396j = hash_pad(bf, 2 * bs, j, byte_count, true, bs);397break;398case CE_ID_HASH_SHA1:399case CE_ID_HASH_SHA224:400case CE_ID_HASH_SHA256:401j = hash_pad(bf, 2 * bs, j, byte_count, false, bs);402break;403case CE_ID_HASH_SHA384:404case CE_ID_HASH_SHA512:405j = hash_pad(bf, 2 * bs, j, byte_count, false, bs);406break;407}408if (!j) {409err = -EINVAL;410goto err_unmap_result;411}412413rctx->pad_len = j * 4;414rctx->addr_pad = dma_map_single(ce->dev, rctx->pad, rctx->pad_len,415DMA_TO_DEVICE);416cet->t_src[i].addr = desc_addr_val_le32(ce, rctx->addr_pad);417cet->t_src[i].len = cpu_to_le32(j);418if (dma_mapping_error(ce->dev, rctx->addr_pad)) {419dev_err(ce->dev, "DMA error on padding SG\n");420err = -EINVAL;421goto err_unmap_result;422}423424if (ce->variant->hash_t_dlen_in_bits)425cet->t_dlen = cpu_to_le32((areq->nbytes + j * 4) * 8);426else427cet->t_dlen = cpu_to_le32(areq->nbytes / 4 + j);428429return 0;430431err_unmap_result:432dma_unmap_single(ce->dev, rctx->addr_res, rctx->result_len,433DMA_FROM_DEVICE);434435err_unmap_src:436dma_unmap_sg(ce->dev, areq->src, rctx->nr_sgs, DMA_TO_DEVICE);437438err_out:439return err;440}441442static void sun8i_ce_hash_unprepare(struct ahash_request *areq,443struct ce_task *cet)444{445struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx_dma(areq);446struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);447struct sun8i_ce_hash_tfm_ctx *ctx = crypto_ahash_ctx(tfm);448struct sun8i_ce_dev *ce = ctx->ce;449450dma_unmap_single(ce->dev, rctx->addr_pad, rctx->pad_len, DMA_TO_DEVICE);451dma_unmap_single(ce->dev, rctx->addr_res, rctx->result_len,452DMA_FROM_DEVICE);453dma_unmap_sg(ce->dev, areq->src, rctx->nr_sgs, DMA_TO_DEVICE);454}455456int sun8i_ce_hash_run(struct crypto_engine *engine, void *async_req)457{458struct ahash_request *areq = ahash_request_cast(async_req);459struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);460struct sun8i_ce_hash_tfm_ctx *ctx = crypto_ahash_ctx(tfm);461struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx_dma(areq);462struct sun8i_ce_dev *ce = ctx->ce;463struct sun8i_ce_flow *chan;464int err;465466chan = &ce->chanlist[rctx->flow];467468err = sun8i_ce_hash_prepare(areq, chan->tl);469if (err)470return err;471472err = sun8i_ce_run_task(ce, rctx->flow, crypto_ahash_alg_name(tfm));473474sun8i_ce_hash_unprepare(areq, chan->tl);475476if (!err)477memcpy(areq->result, rctx->result,478crypto_ahash_digestsize(tfm));479480local_bh_disable();481crypto_finalize_hash_request(engine, async_req, err);482local_bh_enable();483484return 0;485}486487488