The device can only process one request at a time. So if multiple requests came at the same time, we can enqueue them first, and dequeue them one by one when the device is idle. Signed-off-by: zain wang <wzz@xxxxxxxxxxxxxx> --- drivers/crypto/rockchip/rk3288_crypto.c | 46 ++++++- drivers/crypto/rockchip/rk3288_crypto.h | 11 +- drivers/crypto/rockchip/rk3288_crypto_ablkcipher.c | 118 ++++++++---------- drivers/crypto/rockchip/rk3288_crypto_ahash.c | 133 ++++++++++----------- 4 files changed, 160 insertions(+), 148 deletions(-) diff --git a/drivers/crypto/rockchip/rk3288_crypto.c b/drivers/crypto/rockchip/rk3288_crypto.c index 57c3783..c9d622a 100644 --- a/drivers/crypto/rockchip/rk3288_crypto.c +++ b/drivers/crypto/rockchip/rk3288_crypto.c @@ -184,15 +184,53 @@ static irqreturn_t rk_crypto_irq_handle(int irq, void *dev_id) return IRQ_HANDLED; } +static int rk_crypto_enqueue(struct rk_crypto_info *dev, + struct crypto_async_request *async_req) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&dev->lock, flags); + ret = crypto_enqueue_request(&dev->queue, async_req); + if (dev->busy) { + spin_unlock_irqrestore(&dev->lock, flags); + return ret; + } + dev->busy = true; + spin_unlock_irqrestore(&dev->lock, flags); + tasklet_schedule(&dev->queue_task); + + return ret; +} + static void rk_crypto_queue_task_cb(unsigned long data) { struct rk_crypto_info *dev = (struct rk_crypto_info *)data; + struct crypto_async_request *async_req, *backlog; + unsigned long flags; int err = 0; dev->err = 0; + spin_lock_irqsave(&dev->lock, flags); + backlog = crypto_get_backlog(&dev->queue); + async_req = crypto_dequeue_request(&dev->queue); + + if (!async_req) { + dev->busy = false; + spin_unlock_irqrestore(&dev->lock, flags); + return; + } + spin_unlock_irqrestore(&dev->lock, flags); + + if (backlog) { + backlog->complete(backlog, -EINPROGRESS); + backlog = NULL; + } + + dev->async_req = async_req; err = dev->start(dev); if (err) - dev->complete(dev, err); + dev->complete(dev->async_req, err); } static void rk_crypto_done_task_cb(unsigned long data) @@ -200,13 +238,13 @@ static void rk_crypto_done_task_cb(unsigned long data) struct rk_crypto_info *dev = (struct rk_crypto_info *)data; if (dev->err) { - dev->complete(dev, dev->err); + dev->complete(dev->async_req, dev->err); return; } dev->err = dev->update(dev); if (dev->err) - dev->complete(dev, dev->err); + dev->complete(dev->async_req, dev->err); } static struct rk_crypto_tmp *rk_cipher_algs[] = { @@ -365,6 +403,8 @@ static int rk_crypto_probe(struct platform_device *pdev) crypto_info->disable_clk = rk_crypto_disable_clk; crypto_info->load_data = rk_load_data; crypto_info->unload_data = rk_unload_data; + crypto_info->enqueue = rk_crypto_enqueue; + crypto_info->busy = false; err = rk_crypto_register(crypto_info); if (err) { diff --git a/drivers/crypto/rockchip/rk3288_crypto.h b/drivers/crypto/rockchip/rk3288_crypto.h index 65ad1c2..ab6a1b4 100644 --- a/drivers/crypto/rockchip/rk3288_crypto.h +++ b/drivers/crypto/rockchip/rk3288_crypto.h @@ -192,8 +192,7 @@ struct rk_crypto_info { struct crypto_queue queue; struct tasklet_struct queue_task; struct tasklet_struct done_task; - struct ablkcipher_request *ablk_req; - struct ahash_request *ahash_req; + struct crypto_async_request *async_req; int err; /* device lock */ spinlock_t lock; @@ -210,18 +209,20 @@ struct rk_crypto_info { size_t nents; unsigned int total; unsigned int count; - u32 mode; dma_addr_t addr_in; dma_addr_t addr_out; + bool busy; int (*start)(struct rk_crypto_info *dev); int (*update)(struct rk_crypto_info *dev); - void (*complete)(struct rk_crypto_info *dev, int err); + void (*complete)(struct crypto_async_request *base, int err); int (*enable_clk)(struct rk_crypto_info *dev); void (*disable_clk)(struct rk_crypto_info *dev); int (*load_data)(struct rk_crypto_info *dev, struct scatterlist *sg_src, struct scatterlist *sg_dst); void (*unload_data)(struct rk_crypto_info *dev); + int (*enqueue)(struct rk_crypto_info *dev, + struct crypto_async_request *async_req); }; /* the private variable of hash */ @@ -234,12 +235,14 @@ struct rk_ahash_ctx { /* the privete variable of hash for fallback */ struct rk_ahash_rctx { struct ahash_request fallback_req; + u32 mode; }; /* the private variable of cipher */ struct rk_cipher_ctx { struct rk_crypto_info *dev; unsigned int keylen; + u32 mode; }; enum alg_type { diff --git a/drivers/crypto/rockchip/rk3288_crypto_ablkcipher.c b/drivers/crypto/rockchip/rk3288_crypto_ablkcipher.c index dbe78de..639c15c 100644 --- a/drivers/crypto/rockchip/rk3288_crypto_ablkcipher.c +++ b/drivers/crypto/rockchip/rk3288_crypto_ablkcipher.c @@ -15,50 +15,19 @@ #define RK_CRYPTO_DEC BIT(0) -static void rk_crypto_complete(struct rk_crypto_info *dev, int err) +static void rk_crypto_complete(struct crypto_async_request *base, int err) { - if (dev->ablk_req->base.complete) - dev->ablk_req->base.complete(&dev->ablk_req->base, err); + if (base->complete) + base->complete(base, err); } static int rk_handle_req(struct rk_crypto_info *dev, struct ablkcipher_request *req) { - unsigned long flags; - struct crypto_async_request *async_req, *backlog; - int err; - if (!IS_ALIGNED(req->nbytes, dev->align_size)) return -EINVAL; - - dev->left_bytes = req->nbytes; - dev->total = req->nbytes; - dev->sg_src = req->src; - dev->first = req->src; - dev->nents = sg_nents(req->src); - dev->sg_dst = req->dst; - dev->aligned = 1; - dev->ablk_req = req; - - spin_lock_irqsave(&dev->lock, flags); - err = ablkcipher_enqueue_request(&dev->queue, req); - backlog = crypto_get_backlog(&dev->queue); - async_req = crypto_dequeue_request(&dev->queue); - spin_unlock_irqrestore(&dev->lock, flags); - - if (!async_req) { - dev_err(dev->dev, "async_req is NULL !!\n"); - return err; - } - if (backlog) { - backlog->complete(backlog, -EINPROGRESS); - backlog = NULL; - } - - dev->ablk_req = ablkcipher_request_cast(async_req); - - tasklet_schedule(&dev->queue_task); - return err; + else + return dev->enqueue(dev, &req->base); } static int rk_aes_setkey(struct crypto_ablkcipher *cipher, @@ -108,7 +77,7 @@ static int rk_aes_ecb_encrypt(struct ablkcipher_request *req) struct rk_cipher_ctx *ctx = crypto_ablkcipher_ctx(tfm); struct rk_crypto_info *dev = ctx->dev; - dev->mode = RK_CRYPTO_AES_ECB_MODE; + ctx->mode = RK_CRYPTO_AES_ECB_MODE; return rk_handle_req(dev, req); } @@ -118,7 +87,7 @@ static int rk_aes_ecb_decrypt(struct ablkcipher_request *req) struct rk_cipher_ctx *ctx = crypto_ablkcipher_ctx(tfm); struct rk_crypto_info *dev = ctx->dev; - dev->mode = RK_CRYPTO_AES_ECB_MODE | RK_CRYPTO_DEC; + ctx->mode = RK_CRYPTO_AES_ECB_MODE | RK_CRYPTO_DEC; return rk_handle_req(dev, req); } @@ -128,7 +97,7 @@ static int rk_aes_cbc_encrypt(struct ablkcipher_request *req) struct rk_cipher_ctx *ctx = crypto_ablkcipher_ctx(tfm); struct rk_crypto_info *dev = ctx->dev; - dev->mode = RK_CRYPTO_AES_CBC_MODE; + ctx->mode = RK_CRYPTO_AES_CBC_MODE; return rk_handle_req(dev, req); } @@ -138,7 +107,7 @@ static int rk_aes_cbc_decrypt(struct ablkcipher_request *req) struct rk_cipher_ctx *ctx = crypto_ablkcipher_ctx(tfm); struct rk_crypto_info *dev = ctx->dev; - dev->mode = RK_CRYPTO_AES_CBC_MODE | RK_CRYPTO_DEC; + ctx->mode = RK_CRYPTO_AES_CBC_MODE | RK_CRYPTO_DEC; return rk_handle_req(dev, req); } @@ -148,7 +117,7 @@ static int rk_des_ecb_encrypt(struct ablkcipher_request *req) struct rk_cipher_ctx *ctx = crypto_ablkcipher_ctx(tfm); struct rk_crypto_info *dev = ctx->dev; - dev->mode = 0; + ctx->mode = 0; return rk_handle_req(dev, req); } @@ -158,7 +127,7 @@ static int rk_des_ecb_decrypt(struct ablkcipher_request *req) struct rk_cipher_ctx *ctx = crypto_ablkcipher_ctx(tfm); struct rk_crypto_info *dev = ctx->dev; - dev->mode = RK_CRYPTO_DEC; + ctx->mode = RK_CRYPTO_DEC; return rk_handle_req(dev, req); } @@ -168,7 +137,7 @@ static int rk_des_cbc_encrypt(struct ablkcipher_request *req) struct rk_cipher_ctx *ctx = crypto_ablkcipher_ctx(tfm); struct rk_crypto_info *dev = ctx->dev; - dev->mode = RK_CRYPTO_TDES_CHAINMODE_CBC; + ctx->mode = RK_CRYPTO_TDES_CHAINMODE_CBC; return rk_handle_req(dev, req); } @@ -178,7 +147,7 @@ static int rk_des_cbc_decrypt(struct ablkcipher_request *req) struct rk_cipher_ctx *ctx = crypto_ablkcipher_ctx(tfm); struct rk_crypto_info *dev = ctx->dev; - dev->mode = RK_CRYPTO_TDES_CHAINMODE_CBC | RK_CRYPTO_DEC; + ctx->mode = RK_CRYPTO_TDES_CHAINMODE_CBC | RK_CRYPTO_DEC; return rk_handle_req(dev, req); } @@ -188,7 +157,7 @@ static int rk_des3_ede_ecb_encrypt(struct ablkcipher_request *req) struct rk_cipher_ctx *ctx = crypto_ablkcipher_ctx(tfm); struct rk_crypto_info *dev = ctx->dev; - dev->mode = RK_CRYPTO_TDES_SELECT; + ctx->mode = RK_CRYPTO_TDES_SELECT; return rk_handle_req(dev, req); } @@ -198,7 +167,7 @@ static int rk_des3_ede_ecb_decrypt(struct ablkcipher_request *req) struct rk_cipher_ctx *ctx = crypto_ablkcipher_ctx(tfm); struct rk_crypto_info *dev = ctx->dev; - dev->mode = RK_CRYPTO_TDES_SELECT | RK_CRYPTO_DEC; + ctx->mode = RK_CRYPTO_TDES_SELECT | RK_CRYPTO_DEC; return rk_handle_req(dev, req); } @@ -208,7 +177,7 @@ static int rk_des3_ede_cbc_encrypt(struct ablkcipher_request *req) struct rk_cipher_ctx *ctx = crypto_ablkcipher_ctx(tfm); struct rk_crypto_info *dev = ctx->dev; - dev->mode = RK_CRYPTO_TDES_SELECT | RK_CRYPTO_TDES_CHAINMODE_CBC; + ctx->mode = RK_CRYPTO_TDES_SELECT | RK_CRYPTO_TDES_CHAINMODE_CBC; return rk_handle_req(dev, req); } @@ -218,15 +187,16 @@ static int rk_des3_ede_cbc_decrypt(struct ablkcipher_request *req) struct rk_cipher_ctx *ctx = crypto_ablkcipher_ctx(tfm); struct rk_crypto_info *dev = ctx->dev; - dev->mode = RK_CRYPTO_TDES_SELECT | RK_CRYPTO_TDES_CHAINMODE_CBC | + ctx->mode = RK_CRYPTO_TDES_SELECT | RK_CRYPTO_TDES_CHAINMODE_CBC | RK_CRYPTO_DEC; return rk_handle_req(dev, req); } static void rk_ablk_hw_init(struct rk_crypto_info *dev) { - struct crypto_ablkcipher *cipher = - crypto_ablkcipher_reqtfm(dev->ablk_req); + struct ablkcipher_request *req = + ablkcipher_request_cast(dev->async_req); + struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(req); struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher); struct rk_cipher_ctx *ctx = crypto_ablkcipher_ctx(cipher); u32 ivsize, block, conf_reg = 0; @@ -235,25 +205,23 @@ static void rk_ablk_hw_init(struct rk_crypto_info *dev) ivsize = crypto_ablkcipher_ivsize(cipher); if (block == DES_BLOCK_SIZE) { - dev->mode |= RK_CRYPTO_TDES_FIFO_MODE | + ctx->mode |= RK_CRYPTO_TDES_FIFO_MODE | RK_CRYPTO_TDES_BYTESWAP_KEY | RK_CRYPTO_TDES_BYTESWAP_IV; - CRYPTO_WRITE(dev, RK_CRYPTO_TDES_CTRL, dev->mode); - memcpy_toio(dev->reg + RK_CRYPTO_TDES_IV_0, - dev->ablk_req->info, ivsize); + CRYPTO_WRITE(dev, RK_CRYPTO_TDES_CTRL, ctx->mode); + memcpy_toio(dev->reg + RK_CRYPTO_TDES_IV_0, req->info, ivsize); conf_reg = RK_CRYPTO_DESSEL; } else { - dev->mode |= RK_CRYPTO_AES_FIFO_MODE | + ctx->mode |= RK_CRYPTO_AES_FIFO_MODE | RK_CRYPTO_AES_KEY_CHANGE | RK_CRYPTO_AES_BYTESWAP_KEY | RK_CRYPTO_AES_BYTESWAP_IV; if (ctx->keylen == AES_KEYSIZE_192) - dev->mode |= RK_CRYPTO_AES_192BIT_key; + ctx->mode |= RK_CRYPTO_AES_192BIT_key; else if (ctx->keylen == AES_KEYSIZE_256) - dev->mode |= RK_CRYPTO_AES_256BIT_key; - CRYPTO_WRITE(dev, RK_CRYPTO_AES_CTRL, dev->mode); - memcpy_toio(dev->reg + RK_CRYPTO_AES_IV_0, - dev->ablk_req->info, ivsize); + ctx->mode |= RK_CRYPTO_AES_256BIT_key; + CRYPTO_WRITE(dev, RK_CRYPTO_AES_CTRL, ctx->mode); + memcpy_toio(dev->reg + RK_CRYPTO_AES_IV_0, req->info, ivsize); } conf_reg |= RK_CRYPTO_BYTESWAP_BTFIFO | RK_CRYPTO_BYTESWAP_BRFIFO; @@ -283,8 +251,18 @@ static int rk_set_data_start(struct rk_crypto_info *dev) static int rk_ablk_start(struct rk_crypto_info *dev) { + struct ablkcipher_request *req = + ablkcipher_request_cast(dev->async_req); unsigned long flags; - int err; + int err = 0; + + dev->left_bytes = req->nbytes; + dev->total = req->nbytes; + dev->sg_src = req->src; + dev->first = req->src; + dev->nents = sg_nents(req->src); + dev->sg_dst = req->dst; + dev->aligned = 1; spin_lock_irqsave(&dev->lock, flags); rk_ablk_hw_init(dev); @@ -295,15 +273,16 @@ static int rk_ablk_start(struct rk_crypto_info *dev) static void rk_iv_copyback(struct rk_crypto_info *dev) { - struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(dev->ablk_req); + struct ablkcipher_request *req = + ablkcipher_request_cast(dev->async_req); + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); u32 ivsize = crypto_ablkcipher_ivsize(tfm); if (ivsize == DES_BLOCK_SIZE) - memcpy_fromio(dev->ablk_req->info, - dev->reg + RK_CRYPTO_TDES_IV_0, ivsize); + memcpy_fromio(req->info, dev->reg + RK_CRYPTO_TDES_IV_0, + ivsize); else if (ivsize == AES_BLOCK_SIZE) - memcpy_fromio(dev->ablk_req->info, - dev->reg + RK_CRYPTO_AES_IV_0, ivsize); + memcpy_fromio(req->info, dev->reg + RK_CRYPTO_AES_IV_0, ivsize); } /* return: @@ -313,10 +292,12 @@ static void rk_iv_copyback(struct rk_crypto_info *dev) static int rk_ablk_rx(struct rk_crypto_info *dev) { int err = 0; + struct ablkcipher_request *req = + ablkcipher_request_cast(dev->async_req); dev->unload_data(dev); if (!dev->aligned) { - if (!sg_pcopy_from_buffer(dev->ablk_req->dst, dev->nents, + if (!sg_pcopy_from_buffer(req->dst, dev->nents, dev->addr_vir, dev->count, dev->total - dev->left_bytes - dev->count)) { @@ -339,7 +320,8 @@ static int rk_ablk_rx(struct rk_crypto_info *dev) } else { rk_iv_copyback(dev); /* here show the calculation is over without any err */ - dev->complete(dev, 0); + dev->complete(dev->async_req, 0); + tasklet_schedule(&dev->queue_task); } out_rx: return err; diff --git a/drivers/crypto/rockchip/rk3288_crypto_ahash.c b/drivers/crypto/rockchip/rk3288_crypto_ahash.c index ebc46e0..821a506 100644 --- a/drivers/crypto/rockchip/rk3288_crypto_ahash.c +++ b/drivers/crypto/rockchip/rk3288_crypto_ahash.c @@ -40,14 +40,16 @@ static int zero_message_process(struct ahash_request *req) return 0; } -static void rk_ahash_crypto_complete(struct rk_crypto_info *dev, int err) +static void rk_ahash_crypto_complete(struct crypto_async_request *base, int err) { - if (dev->ahash_req->base.complete) - dev->ahash_req->base.complete(&dev->ahash_req->base, err); + if (base->complete) + base->complete(base, err); } static void rk_ahash_reg_init(struct rk_crypto_info *dev) { + struct ahash_request *req = ahash_request_cast(dev->async_req); + struct rk_ahash_rctx *rctx = ahash_request_ctx(req); int reg_status = 0; reg_status = CRYPTO_READ(dev, RK_CRYPTO_CTRL) | @@ -67,7 +69,7 @@ static void rk_ahash_reg_init(struct rk_crypto_info *dev) CRYPTO_WRITE(dev, RK_CRYPTO_INTSTS, RK_CRYPTO_HRDMA_ERR_INT | RK_CRYPTO_HRDMA_DONE_INT); - CRYPTO_WRITE(dev, RK_CRYPTO_HASH_CTRL, dev->mode | + CRYPTO_WRITE(dev, RK_CRYPTO_HASH_CTRL, rctx->mode | RK_CRYPTO_HASH_SWAP_DO); CRYPTO_WRITE(dev, RK_CRYPTO_CONF, RK_CRYPTO_BYTESWAP_HRFIFO | @@ -164,78 +166,13 @@ static int rk_ahash_export(struct ahash_request *req, void *out) static int rk_ahash_digest(struct ahash_request *req) { - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct rk_ahash_ctx *tctx = crypto_tfm_ctx(req->base.tfm); - struct crypto_async_request *async_req, *backlog; - struct rk_crypto_info *dev = NULL; - unsigned long flags; - int ret; + struct rk_crypto_info *dev = tctx->dev; if (!req->nbytes) return zero_message_process(req); - - dev = tctx->dev; - dev->total = req->nbytes; - dev->left_bytes = req->nbytes; - dev->aligned = 0; - dev->mode = 0; - dev->align_size = 4; - dev->sg_dst = NULL; - dev->sg_src = req->src; - dev->first = req->src; - dev->nents = sg_nents(req->src); - - switch (crypto_ahash_digestsize(tfm)) { - case SHA1_DIGEST_SIZE: - dev->mode = RK_CRYPTO_HASH_SHA1; - break; - case SHA256_DIGEST_SIZE: - dev->mode = RK_CRYPTO_HASH_SHA256; - break; - case MD5_DIGEST_SIZE: - dev->mode = RK_CRYPTO_HASH_MD5; - break; - default: - return -EINVAL; - } - - rk_ahash_reg_init(dev); - - spin_lock_irqsave(&dev->lock, flags); - ret = crypto_enqueue_request(&dev->queue, &req->base); - backlog = crypto_get_backlog(&dev->queue); - async_req = crypto_dequeue_request(&dev->queue); - spin_unlock_irqrestore(&dev->lock, flags); - - if (!async_req) { - dev_err(dev->dev, "async_req is NULL !!\n"); - return ret; - } - if (backlog) { - backlog->complete(backlog, -EINPROGRESS); - backlog = NULL; - } - - dev->ahash_req = ahash_request_cast(async_req); - - tasklet_schedule(&dev->queue_task); - - /* - * it will take some time to process date after last dma transmission. - * - * waiting time is relative with the last date len, - * so cannot set a fixed time here. - * 10-50 makes system not call here frequently wasting - * efficiency, and make it response quickly when dma - * complete. - */ - while (!CRYPTO_READ(dev, RK_CRYPTO_HASH_STS)) - usleep_range(10, 50); - - memcpy_fromio(req->result, dev->reg + RK_CRYPTO_HASH_DOUT_0, - crypto_ahash_digestsize(tfm)); - - return 0; + else + return dev->enqueue(dev, &req->base); } static void crypto_ahash_dma_start(struct rk_crypto_info *dev) @@ -258,12 +195,45 @@ static int rk_ahash_set_data_start(struct rk_crypto_info *dev) static int rk_ahash_start(struct rk_crypto_info *dev) { + struct ahash_request *req = ahash_request_cast(dev->async_req); + struct crypto_ahash *tfm; + struct rk_ahash_rctx *rctx; + + dev->total = req->nbytes; + dev->left_bytes = req->nbytes; + dev->aligned = 0; + dev->align_size = 4; + dev->sg_dst = NULL; + dev->sg_src = req->src; + dev->first = req->src; + dev->nents = sg_nents(req->src); + rctx = ahash_request_ctx(req); + rctx->mode = 0; + + tfm = crypto_ahash_reqtfm(req); + switch (crypto_ahash_digestsize(tfm)) { + case SHA1_DIGEST_SIZE: + rctx->mode = RK_CRYPTO_HASH_SHA1; + break; + case SHA256_DIGEST_SIZE: + rctx->mode = RK_CRYPTO_HASH_SHA256; + break; + case MD5_DIGEST_SIZE: + rctx->mode = RK_CRYPTO_HASH_MD5; + break; + default: + return -EINVAL; + } + + rk_ahash_reg_init(dev); return rk_ahash_set_data_start(dev); } static int rk_ahash_crypto_rx(struct rk_crypto_info *dev) { int err = 0; + struct ahash_request *req = ahash_request_cast(dev->async_req); + struct crypto_ahash *tfm; dev->unload_data(dev); if (dev->left_bytes) { @@ -278,7 +248,24 @@ static int rk_ahash_crypto_rx(struct rk_crypto_info *dev) } err = rk_ahash_set_data_start(dev); } else { - dev->complete(dev, 0); + /* + * it will take some time to process date after last dma + * transmission. + * + * waiting time is relative with the last date len, + * so cannot set a fixed time here. + * 10us makes system not call here frequently wasting + * efficiency, and make it response quickly when dma + * complete. + */ + while (!CRYPTO_READ(dev, RK_CRYPTO_HASH_STS)) + udelay(10); + + tfm = crypto_ahash_reqtfm(req); + memcpy_fromio(req->result, dev->reg + RK_CRYPTO_HASH_DOUT_0, + crypto_ahash_digestsize(tfm)); + dev->complete(dev->async_req, 0); + tasklet_schedule(&dev->queue_task); } out_rx: -- 1.9.1