Path: blob/master/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c
26292 views
// SPDX-License-Identifier: GPL-2.01/*2* sun8i-ss-hash.c - hardware cryptographic offloader for3* Allwinner A80/A83T SoC4*5* Copyright (C) 2015-2020 Corentin Labbe <[email protected]>6*7* This file add support for MD5 and SHA1/SHA224/SHA256.8*9* You could find the datasheet in Documentation/arch/arm/sunxi.rst10*/1112#include <crypto/hmac.h>13#include <crypto/internal/hash.h>14#include <crypto/md5.h>15#include <crypto/scatterwalk.h>16#include <crypto/sha1.h>17#include <crypto/sha2.h>18#include <linux/bottom_half.h>19#include <linux/dma-mapping.h>20#include <linux/err.h>21#include <linux/kernel.h>22#include <linux/pm_runtime.h>23#include <linux/scatterlist.h>24#include <linux/slab.h>25#include <linux/string.h>26#include "sun8i-ss.h"2728static int sun8i_ss_hashkey(struct sun8i_ss_hash_tfm_ctx *tfmctx, const u8 *key,29unsigned int keylen)30{31struct crypto_shash *xtfm;32int ret;3334xtfm = crypto_alloc_shash("sha1", 0, CRYPTO_ALG_NEED_FALLBACK);35if (IS_ERR(xtfm))36return PTR_ERR(xtfm);3738ret = crypto_shash_tfm_digest(xtfm, key, keylen, tfmctx->key);39if (ret)40dev_err(tfmctx->ss->dev, "shash digest error ret=%d\n", ret);4142crypto_free_shash(xtfm);43return ret;44}4546int sun8i_ss_hmac_setkey(struct crypto_ahash *ahash, const u8 *key,47unsigned int keylen)48{49struct sun8i_ss_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(ahash);50int digestsize, i;51int bs = crypto_ahash_blocksize(ahash);52int ret;5354digestsize = crypto_ahash_digestsize(ahash);5556if (keylen > bs) {57ret = sun8i_ss_hashkey(tfmctx, key, keylen);58if (ret)59return ret;60tfmctx->keylen = digestsize;61} else {62tfmctx->keylen = keylen;63memcpy(tfmctx->key, key, keylen);64}6566tfmctx->ipad = kzalloc(bs, GFP_KERNEL);67if (!tfmctx->ipad)68return -ENOMEM;69tfmctx->opad = kzalloc(bs, GFP_KERNEL);70if (!tfmctx->opad) {71ret = -ENOMEM;72goto err_opad;73}7475memset(tfmctx->key + tfmctx->keylen, 0, bs - tfmctx->keylen);76memcpy(tfmctx->ipad, tfmctx->key, tfmctx->keylen);77memcpy(tfmctx->opad, tfmctx->key, tfmctx->keylen);78for (i = 0; i < bs; i++) {79tfmctx->ipad[i] ^= HMAC_IPAD_VALUE;80tfmctx->opad[i] ^= HMAC_OPAD_VALUE;81}8283ret = crypto_ahash_setkey(tfmctx->fallback_tfm, key, keylen);84if (!ret)85return 0;8687memzero_explicit(tfmctx->key, keylen);88kfree_sensitive(tfmctx->opad);89err_opad:90kfree_sensitive(tfmctx->ipad);91return ret;92}9394int sun8i_ss_hash_init_tfm(struct crypto_ahash *tfm)95{96struct sun8i_ss_hash_tfm_ctx *op = crypto_ahash_ctx(tfm);97struct ahash_alg *alg = crypto_ahash_alg(tfm);98struct sun8i_ss_alg_template *algt;99int err;100101algt = container_of(alg, struct sun8i_ss_alg_template, alg.hash.base);102op->ss = algt->ss;103104/* FALLBACK */105op->fallback_tfm = crypto_alloc_ahash(crypto_ahash_alg_name(tfm), 0,106CRYPTO_ALG_NEED_FALLBACK);107if (IS_ERR(op->fallback_tfm)) {108dev_err(algt->ss->dev, "Fallback driver could no be loaded\n");109return PTR_ERR(op->fallback_tfm);110}111112crypto_ahash_set_statesize(tfm,113crypto_ahash_statesize(op->fallback_tfm));114115crypto_ahash_set_reqsize(tfm,116sizeof(struct sun8i_ss_hash_reqctx) +117crypto_ahash_reqsize(op->fallback_tfm));118119memcpy(algt->fbname, crypto_ahash_driver_name(op->fallback_tfm),120CRYPTO_MAX_ALG_NAME);121122err = pm_runtime_get_sync(op->ss->dev);123if (err < 0)124goto error_pm;125return 0;126error_pm:127pm_runtime_put_noidle(op->ss->dev);128crypto_free_ahash(op->fallback_tfm);129return err;130}131132void sun8i_ss_hash_exit_tfm(struct crypto_ahash *tfm)133{134struct sun8i_ss_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);135136kfree_sensitive(tfmctx->ipad);137kfree_sensitive(tfmctx->opad);138139crypto_free_ahash(tfmctx->fallback_tfm);140pm_runtime_put_sync_suspend(tfmctx->ss->dev);141}142143int sun8i_ss_hash_init(struct ahash_request *areq)144{145struct sun8i_ss_hash_reqctx *rctx = ahash_request_ctx(areq);146struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);147struct sun8i_ss_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);148149memset(rctx, 0, sizeof(struct sun8i_ss_hash_reqctx));150151ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);152ahash_request_set_callback(&rctx->fallback_req,153areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP,154areq->base.complete, areq->base.data);155156return crypto_ahash_init(&rctx->fallback_req);157}158159int sun8i_ss_hash_export(struct ahash_request *areq, void *out)160{161struct sun8i_ss_hash_reqctx *rctx = ahash_request_ctx(areq);162struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);163struct sun8i_ss_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);164165ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);166ahash_request_set_callback(&rctx->fallback_req,167areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP,168areq->base.complete, areq->base.data);169170return crypto_ahash_export(&rctx->fallback_req, out);171}172173int sun8i_ss_hash_import(struct ahash_request *areq, const void *in)174{175struct sun8i_ss_hash_reqctx *rctx = ahash_request_ctx(areq);176struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);177struct sun8i_ss_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);178179ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);180ahash_request_set_callback(&rctx->fallback_req,181areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP,182areq->base.complete, areq->base.data);183184return crypto_ahash_import(&rctx->fallback_req, in);185}186187int sun8i_ss_hash_final(struct ahash_request *areq)188{189struct sun8i_ss_hash_reqctx *rctx = ahash_request_ctx(areq);190struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);191struct sun8i_ss_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);192193ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);194ahash_request_set_callback(&rctx->fallback_req,195areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP,196areq->base.complete, areq->base.data);197ahash_request_set_crypt(&rctx->fallback_req, NULL, areq->result, 0);198199if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG)) {200struct ahash_alg *alg = crypto_ahash_alg(tfm);201struct sun8i_ss_alg_template *algt __maybe_unused;202203algt = container_of(alg, struct sun8i_ss_alg_template,204alg.hash.base);205206#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG207algt->stat_fb++;208#endif209}210211return crypto_ahash_final(&rctx->fallback_req);212}213214int sun8i_ss_hash_update(struct ahash_request *areq)215{216struct sun8i_ss_hash_reqctx *rctx = ahash_request_ctx(areq);217struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);218struct sun8i_ss_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);219220ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);221ahash_request_set_callback(&rctx->fallback_req,222areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP,223areq->base.complete, areq->base.data);224ahash_request_set_crypt(&rctx->fallback_req, areq->src, NULL, areq->nbytes);225226return crypto_ahash_update(&rctx->fallback_req);227}228229int sun8i_ss_hash_finup(struct ahash_request *areq)230{231struct sun8i_ss_hash_reqctx *rctx = ahash_request_ctx(areq);232struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);233struct sun8i_ss_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);234235ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);236ahash_request_set_callback(&rctx->fallback_req,237areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP,238areq->base.complete, areq->base.data);239ahash_request_set_crypt(&rctx->fallback_req, areq->src, areq->result,240areq->nbytes);241242if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG)) {243struct ahash_alg *alg = crypto_ahash_alg(tfm);244struct sun8i_ss_alg_template *algt __maybe_unused;245246algt = container_of(alg, struct sun8i_ss_alg_template,247alg.hash.base);248249#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG250algt->stat_fb++;251#endif252}253254return crypto_ahash_finup(&rctx->fallback_req);255}256257static int sun8i_ss_hash_digest_fb(struct ahash_request *areq)258{259struct sun8i_ss_hash_reqctx *rctx = ahash_request_ctx(areq);260struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);261struct sun8i_ss_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);262263ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);264ahash_request_set_callback(&rctx->fallback_req,265areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP,266areq->base.complete, areq->base.data);267ahash_request_set_crypt(&rctx->fallback_req, areq->src, areq->result,268areq->nbytes);269270if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG)) {271struct ahash_alg *alg = crypto_ahash_alg(tfm);272struct sun8i_ss_alg_template *algt __maybe_unused;273274algt = container_of(alg, struct sun8i_ss_alg_template,275alg.hash.base);276277#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG278algt->stat_fb++;279#endif280}281282return crypto_ahash_digest(&rctx->fallback_req);283}284285static int sun8i_ss_run_hash_task(struct sun8i_ss_dev *ss,286struct sun8i_ss_hash_reqctx *rctx,287const char *name)288{289int flow = rctx->flow;290u32 v = SS_START;291int i;292293#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG294ss->flows[flow].stat_req++;295#endif296297/* choose between stream0/stream1 */298if (flow)299v |= SS_FLOW1;300else301v |= SS_FLOW0;302303v |= rctx->method;304305for (i = 0; i < MAX_SG; i++) {306if (!rctx->t_dst[i].addr)307break;308309mutex_lock(&ss->mlock);310if (i > 0) {311v |= BIT(17);312writel(rctx->t_dst[i - 1].addr, ss->base + SS_KEY_ADR_REG);313writel(rctx->t_dst[i - 1].addr, ss->base + SS_IV_ADR_REG);314}315316dev_dbg(ss->dev,317"Processing SG %d on flow %d %s ctl=%x %d to %d method=%x src=%x dst=%x\n",318i, flow, name, v,319rctx->t_src[i].len, rctx->t_dst[i].len,320rctx->method, rctx->t_src[i].addr, rctx->t_dst[i].addr);321322writel(rctx->t_src[i].addr, ss->base + SS_SRC_ADR_REG);323writel(rctx->t_dst[i].addr, ss->base + SS_DST_ADR_REG);324writel(rctx->t_src[i].len, ss->base + SS_LEN_ADR_REG);325writel(BIT(0) | BIT(1), ss->base + SS_INT_CTL_REG);326327reinit_completion(&ss->flows[flow].complete);328ss->flows[flow].status = 0;329wmb();330331writel(v, ss->base + SS_CTL_REG);332mutex_unlock(&ss->mlock);333wait_for_completion_interruptible_timeout(&ss->flows[flow].complete,334msecs_to_jiffies(2000));335if (ss->flows[flow].status == 0) {336dev_err(ss->dev, "DMA timeout for %s\n", name);337return -EFAULT;338}339}340341return 0;342}343344static bool sun8i_ss_hash_need_fallback(struct ahash_request *areq)345{346struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);347struct ahash_alg *alg = crypto_ahash_alg(tfm);348struct sun8i_ss_alg_template *algt;349struct scatterlist *sg;350351algt = container_of(alg, struct sun8i_ss_alg_template, alg.hash.base);352353if (areq->nbytes == 0) {354algt->stat_fb_len++;355return true;356}357358if (areq->nbytes >= MAX_PAD_SIZE - 64) {359algt->stat_fb_len++;360return true;361}362363/* we need to reserve one SG for the padding one */364if (sg_nents(areq->src) > MAX_SG - 1) {365algt->stat_fb_sgnum++;366return true;367}368369sg = areq->src;370while (sg) {371/* SS can operate hash only on full block size372* since SS support only MD5,sha1,sha224 and sha256, blocksize373* is always 64374*/375/* Only the last block could be bounced to the pad buffer */376if (sg->length % 64 && sg_next(sg)) {377algt->stat_fb_sglen++;378return true;379}380if (!IS_ALIGNED(sg->offset, sizeof(u32))) {381algt->stat_fb_align++;382return true;383}384if (sg->length % 4) {385algt->stat_fb_sglen++;386return true;387}388sg = sg_next(sg);389}390return false;391}392393int sun8i_ss_hash_digest(struct ahash_request *areq)394{395struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);396struct sun8i_ss_hash_reqctx *rctx = ahash_request_ctx(areq);397struct ahash_alg *alg = crypto_ahash_alg(tfm);398struct sun8i_ss_alg_template *algt;399struct sun8i_ss_dev *ss;400struct crypto_engine *engine;401int e;402403if (sun8i_ss_hash_need_fallback(areq))404return sun8i_ss_hash_digest_fb(areq);405406algt = container_of(alg, struct sun8i_ss_alg_template, alg.hash.base);407ss = algt->ss;408409e = sun8i_ss_get_engine_number(ss);410rctx->flow = e;411engine = ss->flows[e].engine;412413return crypto_transfer_hash_request_to_engine(engine, areq);414}415416static u64 hash_pad(__le32 *buf, unsigned int bufsize, u64 padi, u64 byte_count, bool le, int bs)417{418u64 fill, min_fill, j, k;419__be64 *bebits;420__le64 *lebits;421422j = padi;423buf[j++] = cpu_to_le32(0x80);424425if (bs == 64) {426fill = 64 - (byte_count % 64);427min_fill = 2 * sizeof(u32) + sizeof(u32);428} else {429fill = 128 - (byte_count % 128);430min_fill = 4 * sizeof(u32) + sizeof(u32);431}432433if (fill < min_fill)434fill += bs;435436k = j;437j += (fill - min_fill) / sizeof(u32);438if (j * 4 > bufsize) {439pr_err("%s OVERFLOW %llu\n", __func__, j);440return 0;441}442for (; k < j; k++)443buf[k] = 0;444445if (le) {446/* MD5 */447lebits = (__le64 *)&buf[j];448*lebits = cpu_to_le64(byte_count << 3);449j += 2;450} else {451if (bs == 64) {452/* sha1 sha224 sha256 */453bebits = (__be64 *)&buf[j];454*bebits = cpu_to_be64(byte_count << 3);455j += 2;456} else {457/* sha384 sha512*/458bebits = (__be64 *)&buf[j];459*bebits = cpu_to_be64(byte_count >> 61);460j += 2;461bebits = (__be64 *)&buf[j];462*bebits = cpu_to_be64(byte_count << 3);463j += 2;464}465}466if (j * 4 > bufsize) {467pr_err("%s OVERFLOW %llu\n", __func__, j);468return 0;469}470471return j;472}473474/* sun8i_ss_hash_run - run an ahash request475* Send the data of the request to the SS along with an extra SG with padding476*/477int sun8i_ss_hash_run(struct crypto_engine *engine, void *breq)478{479struct ahash_request *areq = container_of(breq, struct ahash_request, base);480struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);481struct sun8i_ss_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);482struct sun8i_ss_hash_reqctx *rctx = ahash_request_ctx(areq);483struct ahash_alg *alg = crypto_ahash_alg(tfm);484struct sun8i_ss_alg_template *algt;485struct sun8i_ss_dev *ss;486struct scatterlist *sg;487int bs = crypto_ahash_blocksize(tfm);488int nr_sgs, err, digestsize;489unsigned int len;490u64 byte_count;491void *pad, *result;492int j, i, k, todo;493dma_addr_t addr_res, addr_pad, addr_xpad;494__le32 *bf;495/* HMAC step:496* 0: normal hashing497* 1: IPAD498* 2: OPAD499*/500int hmac = 0;501502algt = container_of(alg, struct sun8i_ss_alg_template, alg.hash.base);503ss = algt->ss;504505digestsize = crypto_ahash_digestsize(tfm);506if (digestsize == SHA224_DIGEST_SIZE)507digestsize = SHA256_DIGEST_SIZE;508509result = ss->flows[rctx->flow].result;510pad = ss->flows[rctx->flow].pad;511bf = (__le32 *)pad;512513for (i = 0; i < MAX_SG; i++) {514rctx->t_dst[i].addr = 0;515rctx->t_dst[i].len = 0;516}517518#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG519algt->stat_req++;520#endif521522rctx->method = ss->variant->alg_hash[algt->ss_algo_id];523524nr_sgs = dma_map_sg(ss->dev, areq->src, sg_nents(areq->src), DMA_TO_DEVICE);525if (nr_sgs <= 0 || nr_sgs > MAX_SG) {526dev_err(ss->dev, "Invalid sg number %d\n", nr_sgs);527err = -EINVAL;528goto theend;529}530531addr_res = dma_map_single(ss->dev, result, digestsize, DMA_FROM_DEVICE);532if (dma_mapping_error(ss->dev, addr_res)) {533dev_err(ss->dev, "DMA map dest\n");534err = -EINVAL;535goto err_dma_result;536}537538j = 0;539len = areq->nbytes;540sg = areq->src;541i = 0;542while (len > 0 && sg) {543if (sg_dma_len(sg) == 0) {544sg = sg_next(sg);545continue;546}547todo = min(len, sg_dma_len(sg));548/* only the last SG could be with a size not modulo64 */549if (todo % 64 == 0) {550rctx->t_src[i].addr = sg_dma_address(sg);551rctx->t_src[i].len = todo / 4;552rctx->t_dst[i].addr = addr_res;553rctx->t_dst[i].len = digestsize / 4;554len -= todo;555} else {556scatterwalk_map_and_copy(bf, sg, 0, todo, 0);557j += todo / 4;558len -= todo;559}560sg = sg_next(sg);561i++;562}563if (len > 0) {564dev_err(ss->dev, "remaining len %d\n", len);565err = -EINVAL;566goto theend;567}568569if (j > 0)570i--;571572retry:573byte_count = areq->nbytes;574if (tfmctx->keylen && hmac == 0) {575hmac = 1;576/* shift all SG one slot up, to free slot 0 for IPAD */577for (k = 6; k >= 0; k--) {578rctx->t_src[k + 1].addr = rctx->t_src[k].addr;579rctx->t_src[k + 1].len = rctx->t_src[k].len;580rctx->t_dst[k + 1].addr = rctx->t_dst[k].addr;581rctx->t_dst[k + 1].len = rctx->t_dst[k].len;582}583addr_xpad = dma_map_single(ss->dev, tfmctx->ipad, bs, DMA_TO_DEVICE);584err = dma_mapping_error(ss->dev, addr_xpad);585if (err) {586dev_err(ss->dev, "Fail to create DMA mapping of ipad\n");587goto err_dma_xpad;588}589rctx->t_src[0].addr = addr_xpad;590rctx->t_src[0].len = bs / 4;591rctx->t_dst[0].addr = addr_res;592rctx->t_dst[0].len = digestsize / 4;593i++;594byte_count = areq->nbytes + bs;595}596if (tfmctx->keylen && hmac == 2) {597for (i = 0; i < MAX_SG; i++) {598rctx->t_src[i].addr = 0;599rctx->t_src[i].len = 0;600rctx->t_dst[i].addr = 0;601rctx->t_dst[i].len = 0;602}603604addr_res = dma_map_single(ss->dev, result, digestsize, DMA_FROM_DEVICE);605if (dma_mapping_error(ss->dev, addr_res)) {606dev_err(ss->dev, "Fail to create DMA mapping of result\n");607err = -EINVAL;608goto err_dma_result;609}610addr_xpad = dma_map_single(ss->dev, tfmctx->opad, bs, DMA_TO_DEVICE);611err = dma_mapping_error(ss->dev, addr_xpad);612if (err) {613dev_err(ss->dev, "Fail to create DMA mapping of opad\n");614goto err_dma_xpad;615}616rctx->t_src[0].addr = addr_xpad;617rctx->t_src[0].len = bs / 4;618619memcpy(bf, result, digestsize);620j = digestsize / 4;621i = 1;622byte_count = digestsize + bs;623624rctx->t_dst[0].addr = addr_res;625rctx->t_dst[0].len = digestsize / 4;626}627628switch (algt->ss_algo_id) {629case SS_ID_HASH_MD5:630j = hash_pad(bf, 4096, j, byte_count, true, bs);631break;632case SS_ID_HASH_SHA1:633case SS_ID_HASH_SHA224:634case SS_ID_HASH_SHA256:635j = hash_pad(bf, 4096, j, byte_count, false, bs);636break;637}638if (!j) {639err = -EINVAL;640goto theend;641}642643addr_pad = dma_map_single(ss->dev, pad, j * 4, DMA_TO_DEVICE);644if (dma_mapping_error(ss->dev, addr_pad)) {645dev_err(ss->dev, "DMA error on padding SG\n");646err = -EINVAL;647goto err_dma_pad;648}649rctx->t_src[i].addr = addr_pad;650rctx->t_src[i].len = j;651rctx->t_dst[i].addr = addr_res;652rctx->t_dst[i].len = digestsize / 4;653654err = sun8i_ss_run_hash_task(ss, rctx, crypto_tfm_alg_name(areq->base.tfm));655656/*657* mini helper for checking dma map/unmap658* flow start for hmac = 0 (and HMAC = 1)659* HMAC = 0660* MAP src661* MAP res662*663* retry:664* if hmac then hmac = 1665* MAP xpad (ipad)666* if hmac == 2667* MAP res668* MAP xpad (opad)669* MAP pad670* ACTION!671* UNMAP pad672* if hmac673* UNMAP xpad674* UNMAP res675* if hmac < 2676* UNMAP SRC677*678* if hmac = 1 then hmac = 2 goto retry679*/680681dma_unmap_single(ss->dev, addr_pad, j * 4, DMA_TO_DEVICE);682683err_dma_pad:684if (hmac > 0)685dma_unmap_single(ss->dev, addr_xpad, bs, DMA_TO_DEVICE);686err_dma_xpad:687dma_unmap_single(ss->dev, addr_res, digestsize, DMA_FROM_DEVICE);688err_dma_result:689if (hmac < 2)690dma_unmap_sg(ss->dev, areq->src, sg_nents(areq->src),691DMA_TO_DEVICE);692if (hmac == 1 && !err) {693hmac = 2;694goto retry;695}696697if (!err)698memcpy(areq->result, result, crypto_ahash_digestsize(tfm));699theend:700local_bh_disable();701crypto_finalize_hash_request(engine, breq, err);702local_bh_enable();703return 0;704}705706707