Path: blob/master/drivers/crypto/rockchip/rk3288_crypto_ahash.c
26282 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* Crypto acceleration support for Rockchip RK32883*4* Copyright (c) 2015, Fuzhou Rockchip Electronics Co., Ltd5*6* Author: Zain Wang <[email protected]>7*8* Some ideas are from marvell/cesa.c and s5p-sss.c driver.9*/1011#include <linux/unaligned.h>12#include <crypto/internal/hash.h>13#include <linux/device.h>14#include <linux/err.h>15#include <linux/iopoll.h>16#include <linux/kernel.h>17#include <linux/module.h>18#include <linux/string.h>19#include "rk3288_crypto.h"2021/*22* IC can not process zero message hash,23* so we put the fixed hash out when met zero message.24*/2526static bool rk_ahash_need_fallback(struct ahash_request *req)27{28struct scatterlist *sg;2930sg = req->src;31while (sg) {32if (!IS_ALIGNED(sg->offset, sizeof(u32))) {33return true;34}35if (sg->length % 4) {36return true;37}38sg = sg_next(sg);39}40return false;41}4243static int rk_ahash_digest_fb(struct ahash_request *areq)44{45struct rk_ahash_rctx *rctx = ahash_request_ctx(areq);46struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);47struct rk_ahash_ctx *tfmctx = crypto_ahash_ctx(tfm);48struct ahash_alg *alg = crypto_ahash_alg(tfm);49struct rk_crypto_tmp *algt = container_of(alg, struct rk_crypto_tmp, alg.hash.base);5051algt->stat_fb++;5253ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);54ahash_request_set_callback(&rctx->fallback_req,55areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP,56areq->base.complete, areq->base.data);57ahash_request_set_crypt(&rctx->fallback_req, areq->src, areq->result,58areq->nbytes);5960return crypto_ahash_digest(&rctx->fallback_req);61}6263static int zero_message_process(struct ahash_request *req)64{65struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);66int rk_digest_size = crypto_ahash_digestsize(tfm);6768switch (rk_digest_size) {69case SHA1_DIGEST_SIZE:70memcpy(req->result, sha1_zero_message_hash, rk_digest_size);71break;72case SHA256_DIGEST_SIZE:73memcpy(req->result, sha256_zero_message_hash, rk_digest_size);74break;75case MD5_DIGEST_SIZE:76memcpy(req->result, md5_zero_message_hash, rk_digest_size);77break;78default:79return -EINVAL;80}8182return 0;83}8485static void rk_ahash_reg_init(struct ahash_request *req,86struct rk_crypto_info *dev)87{88struct rk_ahash_rctx *rctx = ahash_request_ctx(req);89int reg_status;9091reg_status = CRYPTO_READ(dev, RK_CRYPTO_CTRL) |92RK_CRYPTO_HASH_FLUSH | _SBF(0xffff, 16);93CRYPTO_WRITE(dev, RK_CRYPTO_CTRL, reg_status);9495reg_status = CRYPTO_READ(dev, RK_CRYPTO_CTRL);96reg_status &= (~RK_CRYPTO_HASH_FLUSH);97reg_status |= _SBF(0xffff, 16);98CRYPTO_WRITE(dev, RK_CRYPTO_CTRL, reg_status);99100memset_io(dev->reg + RK_CRYPTO_HASH_DOUT_0, 0, 32);101102CRYPTO_WRITE(dev, RK_CRYPTO_INTENA, RK_CRYPTO_HRDMA_ERR_ENA |103RK_CRYPTO_HRDMA_DONE_ENA);104105CRYPTO_WRITE(dev, RK_CRYPTO_INTSTS, RK_CRYPTO_HRDMA_ERR_INT |106RK_CRYPTO_HRDMA_DONE_INT);107108CRYPTO_WRITE(dev, RK_CRYPTO_HASH_CTRL, rctx->mode |109RK_CRYPTO_HASH_SWAP_DO);110111CRYPTO_WRITE(dev, RK_CRYPTO_CONF, RK_CRYPTO_BYTESWAP_HRFIFO |112RK_CRYPTO_BYTESWAP_BRFIFO |113RK_CRYPTO_BYTESWAP_BTFIFO);114115CRYPTO_WRITE(dev, RK_CRYPTO_HASH_MSG_LEN, req->nbytes);116}117118static int rk_ahash_init(struct ahash_request *req)119{120struct rk_ahash_rctx *rctx = ahash_request_ctx(req);121struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);122struct rk_ahash_ctx *ctx = crypto_ahash_ctx(tfm);123124ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);125ahash_request_set_callback(&rctx->fallback_req,126req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP,127req->base.complete, req->base.data);128129return crypto_ahash_init(&rctx->fallback_req);130}131132static int rk_ahash_update(struct ahash_request *req)133{134struct rk_ahash_rctx *rctx = ahash_request_ctx(req);135struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);136struct rk_ahash_ctx *ctx = crypto_ahash_ctx(tfm);137138ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);139ahash_request_set_callback(&rctx->fallback_req,140req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP,141req->base.complete, req->base.data);142ahash_request_set_crypt(&rctx->fallback_req, req->src, NULL, req->nbytes);143144return crypto_ahash_update(&rctx->fallback_req);145}146147static int rk_ahash_final(struct ahash_request *req)148{149struct rk_ahash_rctx *rctx = ahash_request_ctx(req);150struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);151struct rk_ahash_ctx *ctx = crypto_ahash_ctx(tfm);152153ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);154ahash_request_set_callback(&rctx->fallback_req,155req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP,156req->base.complete, req->base.data);157ahash_request_set_crypt(&rctx->fallback_req, NULL, req->result, 0);158159return crypto_ahash_final(&rctx->fallback_req);160}161162static int rk_ahash_finup(struct ahash_request *req)163{164struct rk_ahash_rctx *rctx = ahash_request_ctx(req);165struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);166struct rk_ahash_ctx *ctx = crypto_ahash_ctx(tfm);167168ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);169ahash_request_set_callback(&rctx->fallback_req,170req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP,171req->base.complete, req->base.data);172ahash_request_set_crypt(&rctx->fallback_req, req->src, req->result,173req->nbytes);174175return crypto_ahash_finup(&rctx->fallback_req);176}177178static int rk_ahash_import(struct ahash_request *req, const void *in)179{180struct rk_ahash_rctx *rctx = ahash_request_ctx(req);181struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);182struct rk_ahash_ctx *ctx = crypto_ahash_ctx(tfm);183184ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);185ahash_request_set_callback(&rctx->fallback_req,186req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP,187req->base.complete, req->base.data);188189return crypto_ahash_import(&rctx->fallback_req, in);190}191192static int rk_ahash_export(struct ahash_request *req, void *out)193{194struct rk_ahash_rctx *rctx = ahash_request_ctx(req);195struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);196struct rk_ahash_ctx *ctx = crypto_ahash_ctx(tfm);197198ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);199ahash_request_set_callback(&rctx->fallback_req,200req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP,201req->base.complete, req->base.data);202203return crypto_ahash_export(&rctx->fallback_req, out);204}205206static int rk_ahash_digest(struct ahash_request *req)207{208struct rk_ahash_rctx *rctx = ahash_request_ctx(req);209struct rk_crypto_info *dev;210struct crypto_engine *engine;211212if (rk_ahash_need_fallback(req))213return rk_ahash_digest_fb(req);214215if (!req->nbytes)216return zero_message_process(req);217218dev = get_rk_crypto();219220rctx->dev = dev;221engine = dev->engine;222223return crypto_transfer_hash_request_to_engine(engine, req);224}225226static void crypto_ahash_dma_start(struct rk_crypto_info *dev, struct scatterlist *sg)227{228CRYPTO_WRITE(dev, RK_CRYPTO_HRDMAS, sg_dma_address(sg));229CRYPTO_WRITE(dev, RK_CRYPTO_HRDMAL, sg_dma_len(sg) / 4);230CRYPTO_WRITE(dev, RK_CRYPTO_CTRL, RK_CRYPTO_HASH_START |231(RK_CRYPTO_HASH_START << 16));232}233234static int rk_hash_prepare(struct crypto_engine *engine, void *breq)235{236struct ahash_request *areq = container_of(breq, struct ahash_request, base);237struct rk_ahash_rctx *rctx = ahash_request_ctx(areq);238struct rk_crypto_info *rkc = rctx->dev;239int ret;240241ret = dma_map_sg(rkc->dev, areq->src, sg_nents(areq->src), DMA_TO_DEVICE);242if (ret <= 0)243return -EINVAL;244245rctx->nrsg = ret;246247return 0;248}249250static void rk_hash_unprepare(struct crypto_engine *engine, void *breq)251{252struct ahash_request *areq = container_of(breq, struct ahash_request, base);253struct rk_ahash_rctx *rctx = ahash_request_ctx(areq);254struct rk_crypto_info *rkc = rctx->dev;255256dma_unmap_sg(rkc->dev, areq->src, rctx->nrsg, DMA_TO_DEVICE);257}258259static int rk_hash_run(struct crypto_engine *engine, void *breq)260{261struct ahash_request *areq = container_of(breq, struct ahash_request, base);262struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);263struct rk_ahash_rctx *rctx = ahash_request_ctx(areq);264struct ahash_alg *alg = crypto_ahash_alg(tfm);265struct rk_crypto_tmp *algt = container_of(alg, struct rk_crypto_tmp, alg.hash.base);266struct scatterlist *sg = areq->src;267struct rk_crypto_info *rkc = rctx->dev;268int err;269int i;270u32 v;271272err = pm_runtime_resume_and_get(rkc->dev);273if (err)274return err;275276err = rk_hash_prepare(engine, breq);277if (err)278goto theend;279280rctx->mode = 0;281282algt->stat_req++;283rkc->nreq++;284285switch (crypto_ahash_digestsize(tfm)) {286case SHA1_DIGEST_SIZE:287rctx->mode = RK_CRYPTO_HASH_SHA1;288break;289case SHA256_DIGEST_SIZE:290rctx->mode = RK_CRYPTO_HASH_SHA256;291break;292case MD5_DIGEST_SIZE:293rctx->mode = RK_CRYPTO_HASH_MD5;294break;295default:296err = -EINVAL;297goto theend;298}299300rk_ahash_reg_init(areq, rkc);301302while (sg) {303reinit_completion(&rkc->complete);304rkc->status = 0;305crypto_ahash_dma_start(rkc, sg);306wait_for_completion_interruptible_timeout(&rkc->complete,307msecs_to_jiffies(2000));308if (!rkc->status) {309dev_err(rkc->dev, "DMA timeout\n");310err = -EFAULT;311goto theend;312}313sg = sg_next(sg);314}315316/*317* it will take some time to process date after last dma318* transmission.319*320* waiting time is relative with the last date len,321* so cannot set a fixed time here.322* 10us makes system not call here frequently wasting323* efficiency, and make it response quickly when dma324* complete.325*/326readl_poll_timeout(rkc->reg + RK_CRYPTO_HASH_STS, v, v == 0, 10, 1000);327328for (i = 0; i < crypto_ahash_digestsize(tfm) / 4; i++) {329v = readl(rkc->reg + RK_CRYPTO_HASH_DOUT_0 + i * 4);330put_unaligned_le32(v, areq->result + i * 4);331}332333theend:334pm_runtime_put_autosuspend(rkc->dev);335336rk_hash_unprepare(engine, breq);337338local_bh_disable();339crypto_finalize_hash_request(engine, breq, err);340local_bh_enable();341342return 0;343}344345static int rk_hash_init_tfm(struct crypto_ahash *tfm)346{347struct rk_ahash_ctx *tctx = crypto_ahash_ctx(tfm);348const char *alg_name = crypto_ahash_alg_name(tfm);349struct ahash_alg *alg = crypto_ahash_alg(tfm);350struct rk_crypto_tmp *algt = container_of(alg, struct rk_crypto_tmp, alg.hash.base);351352/* for fallback */353tctx->fallback_tfm = crypto_alloc_ahash(alg_name, 0,354CRYPTO_ALG_NEED_FALLBACK);355if (IS_ERR(tctx->fallback_tfm)) {356dev_err(algt->dev->dev, "Could not load fallback driver.\n");357return PTR_ERR(tctx->fallback_tfm);358}359360crypto_ahash_set_reqsize(tfm,361sizeof(struct rk_ahash_rctx) +362crypto_ahash_reqsize(tctx->fallback_tfm));363364return 0;365}366367static void rk_hash_exit_tfm(struct crypto_ahash *tfm)368{369struct rk_ahash_ctx *tctx = crypto_ahash_ctx(tfm);370371crypto_free_ahash(tctx->fallback_tfm);372}373374struct rk_crypto_tmp rk_ahash_sha1 = {375.type = CRYPTO_ALG_TYPE_AHASH,376.alg.hash.base = {377.init = rk_ahash_init,378.update = rk_ahash_update,379.final = rk_ahash_final,380.finup = rk_ahash_finup,381.export = rk_ahash_export,382.import = rk_ahash_import,383.digest = rk_ahash_digest,384.init_tfm = rk_hash_init_tfm,385.exit_tfm = rk_hash_exit_tfm,386.halg = {387.digestsize = SHA1_DIGEST_SIZE,388.statesize = sizeof(struct sha1_state),389.base = {390.cra_name = "sha1",391.cra_driver_name = "rk-sha1",392.cra_priority = 300,393.cra_flags = CRYPTO_ALG_ASYNC |394CRYPTO_ALG_NEED_FALLBACK,395.cra_blocksize = SHA1_BLOCK_SIZE,396.cra_ctxsize = sizeof(struct rk_ahash_ctx),397.cra_module = THIS_MODULE,398}399}400},401.alg.hash.op = {402.do_one_request = rk_hash_run,403},404};405406struct rk_crypto_tmp rk_ahash_sha256 = {407.type = CRYPTO_ALG_TYPE_AHASH,408.alg.hash.base = {409.init = rk_ahash_init,410.update = rk_ahash_update,411.final = rk_ahash_final,412.finup = rk_ahash_finup,413.export = rk_ahash_export,414.import = rk_ahash_import,415.digest = rk_ahash_digest,416.init_tfm = rk_hash_init_tfm,417.exit_tfm = rk_hash_exit_tfm,418.halg = {419.digestsize = SHA256_DIGEST_SIZE,420.statesize = sizeof(struct sha256_state),421.base = {422.cra_name = "sha256",423.cra_driver_name = "rk-sha256",424.cra_priority = 300,425.cra_flags = CRYPTO_ALG_ASYNC |426CRYPTO_ALG_NEED_FALLBACK,427.cra_blocksize = SHA256_BLOCK_SIZE,428.cra_ctxsize = sizeof(struct rk_ahash_ctx),429.cra_module = THIS_MODULE,430}431}432},433.alg.hash.op = {434.do_one_request = rk_hash_run,435},436};437438struct rk_crypto_tmp rk_ahash_md5 = {439.type = CRYPTO_ALG_TYPE_AHASH,440.alg.hash.base = {441.init = rk_ahash_init,442.update = rk_ahash_update,443.final = rk_ahash_final,444.finup = rk_ahash_finup,445.export = rk_ahash_export,446.import = rk_ahash_import,447.digest = rk_ahash_digest,448.init_tfm = rk_hash_init_tfm,449.exit_tfm = rk_hash_exit_tfm,450.halg = {451.digestsize = MD5_DIGEST_SIZE,452.statesize = sizeof(struct md5_state),453.base = {454.cra_name = "md5",455.cra_driver_name = "rk-md5",456.cra_priority = 300,457.cra_flags = CRYPTO_ALG_ASYNC |458CRYPTO_ALG_NEED_FALLBACK,459.cra_blocksize = SHA1_BLOCK_SIZE,460.cra_ctxsize = sizeof(struct rk_ahash_ctx),461.cra_module = THIS_MODULE,462}463}464},465.alg.hash.op = {466.do_one_request = rk_hash_run,467},468};469470471