Skip to content

Commit

Permalink
crypto: rockchip: rework by using crypto_engine
Browse files Browse the repository at this point in the history
Instead of doing manual queue management, let's use the crypto/engine
for that.
In the same time, rework the requests handling to be easier to
understand (and fix all bugs related to them).

Fixes: ce0183c ("crypto: rockchip - switch to skcipher API")
Signed-off-by: Corentin Labbe <clabbe@baylibre.com>
  • Loading branch information
montjoie authored and intel-lab-lkp committed Feb 28, 2022
1 parent abb0ddd commit 7e5f8e4
Show file tree
Hide file tree
Showing 4 changed files with 227 additions and 365 deletions.
150 changes: 7 additions & 143 deletions drivers/crypto/rockchip/rk3288_crypto.c
Expand Up @@ -65,149 +65,24 @@ static void rk_crypto_disable_clk(struct rk_crypto_info *dev)
clk_disable_unprepare(dev->sclk);
}

static int check_alignment(struct scatterlist *sg_src,
struct scatterlist *sg_dst,
int align_mask)
{
int in, out, align;

in = IS_ALIGNED((uint32_t)sg_src->offset, 4) &&
IS_ALIGNED((uint32_t)sg_src->length, align_mask);
if (!sg_dst)
return in;
out = IS_ALIGNED((uint32_t)sg_dst->offset, 4) &&
IS_ALIGNED((uint32_t)sg_dst->length, align_mask);
align = in && out;

return (align && (sg_src->length == sg_dst->length));
}

static int rk_load_data(struct rk_crypto_info *dev,
struct scatterlist *sg_src,
struct scatterlist *sg_dst)
{
unsigned int count;

count = min(dev->left_bytes, sg_src->length);
dev->left_bytes -= count;

if (!dma_map_sg(dev->dev, sg_src, 1, DMA_TO_DEVICE)) {
dev_err(dev->dev, "[%s:%d] dma_map_sg(src) error\n",
__func__, __LINE__);
return -EINVAL;
}
dev->addr_in = sg_dma_address(sg_src);

if (sg_dst) {
if (!dma_map_sg(dev->dev, sg_dst, 1, DMA_FROM_DEVICE)) {
dev_err(dev->dev,
"[%s:%d] dma_map_sg(dst) error\n",
__func__, __LINE__);
dma_unmap_sg(dev->dev, sg_src, 1,
DMA_TO_DEVICE);
return -EINVAL;
}
dev->addr_out = sg_dma_address(sg_dst);
}
dev->count = count;
return 0;
}

static void rk_unload_data(struct rk_crypto_info *dev)
{
struct scatterlist *sg_in, *sg_out;

sg_in = dev->sg_src;
dma_unmap_sg(dev->dev, sg_in, 1, DMA_TO_DEVICE);

if (dev->sg_dst) {
sg_out = dev->sg_dst;
dma_unmap_sg(dev->dev, sg_out, 1, DMA_FROM_DEVICE);
}
}

static irqreturn_t rk_crypto_irq_handle(int irq, void *dev_id)
{
struct rk_crypto_info *dev = platform_get_drvdata(dev_id);
u32 interrupt_status;

spin_lock(&dev->lock);
interrupt_status = CRYPTO_READ(dev, RK_CRYPTO_INTSTS);
CRYPTO_WRITE(dev, RK_CRYPTO_INTSTS, interrupt_status);

dev->status = 1;
if (interrupt_status & 0x0a) {
dev_warn(dev->dev, "DMA Error\n");
dev->err = -EFAULT;
dev->status = 0;
}
tasklet_schedule(&dev->done_task);
complete(&dev->complete);

spin_unlock(&dev->lock);
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->async_req, err);
}

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->async_req, dev->err);
return;
}

dev->err = dev->update(dev);
if (dev->err)
dev->complete(dev->async_req, dev->err);
}

static struct rk_crypto_tmp *rk_cipher_algs[] = {
&rk_ecb_aes_alg,
&rk_cbc_aes_alg,
Expand Down Expand Up @@ -300,8 +175,6 @@ static int rk_crypto_probe(struct platform_device *pdev)
if (err)
goto err_crypto;

spin_lock_init(&crypto_info->lock);

crypto_info->reg = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(crypto_info->reg)) {
err = PTR_ERR(crypto_info->reg);
Expand Down Expand Up @@ -351,17 +224,11 @@ static int rk_crypto_probe(struct platform_device *pdev)
crypto_info->dev = &pdev->dev;
platform_set_drvdata(pdev, crypto_info);

tasklet_init(&crypto_info->queue_task,
rk_crypto_queue_task_cb, (unsigned long)crypto_info);
tasklet_init(&crypto_info->done_task,
rk_crypto_done_task_cb, (unsigned long)crypto_info);
crypto_init_queue(&crypto_info->queue, 50);
crypto_info->engine = crypto_engine_alloc_init(&pdev->dev, true);
crypto_engine_start(crypto_info->engine);
init_completion(&crypto_info->complete);

rk_crypto_enable_clk(crypto_info);
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) {
Expand All @@ -373,9 +240,8 @@ static int rk_crypto_probe(struct platform_device *pdev)
return 0;

err_register_alg:
tasklet_kill(&crypto_info->queue_task);
tasklet_kill(&crypto_info->done_task);
err_crypto:
dev_err(dev, "Crypto Accelerator not successfully registered\n");
return err;
}

Expand All @@ -385,8 +251,6 @@ static int rk_crypto_remove(struct platform_device *pdev)

rk_crypto_unregister();
rk_crypto_disable_clk(crypto_tmp);
tasklet_kill(&crypto_tmp->done_task);
tasklet_kill(&crypto_tmp->queue_task);
return 0;
}

Expand Down
39 changes: 10 additions & 29 deletions drivers/crypto/rockchip/rk3288_crypto.h
Expand Up @@ -5,9 +5,11 @@
#include <crypto/aes.h>
#include <crypto/internal/des.h>
#include <crypto/algapi.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/scatterlist.h>
#include <crypto/engine.h>
#include <crypto/internal/hash.h>
#include <crypto/internal/skcipher.h>

Expand Down Expand Up @@ -193,39 +195,15 @@ struct rk_crypto_info {
struct reset_control *rst;
void __iomem *reg;
int irq;
struct crypto_queue queue;
struct tasklet_struct queue_task;
struct tasklet_struct done_task;
struct crypto_async_request *async_req;
int err;
/* device lock */
spinlock_t lock;

/* the public variable */
struct scatterlist *sg_src;
struct scatterlist *sg_dst;
struct scatterlist *first;
unsigned int left_bytes;
size_t src_nents;
size_t dst_nents;
unsigned int total;
unsigned int count;
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 crypto_async_request *base, int err);
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);

struct crypto_engine *engine;
struct completion complete;
int status;
};

/* the private variable of hash */
struct rk_ahash_ctx {
struct crypto_engine_ctx enginectx;
struct rk_crypto_info *dev;
/* for fallback */
struct crypto_ahash *fallback_tfm;
Expand All @@ -235,10 +213,12 @@ struct rk_ahash_ctx {
struct rk_ahash_rctx {
struct ahash_request fallback_req;
u32 mode;
int nrsg;
};

/* the private variable of cipher */
struct rk_cipher_ctx {
struct crypto_engine_ctx enginectx;
struct rk_crypto_info *dev;
unsigned int keylen;
u32 key[AES_MAX_KEY_SIZE / 4];
Expand All @@ -247,6 +227,7 @@ struct rk_cipher_ctx {
};

struct rk_cipher_rctx {
u8 backup_iv[AES_BLOCK_SIZE];
u32 mode;
struct skcipher_request fallback_req; // keep at the end
};
Expand Down

0 comments on commit 7e5f8e4

Please sign in to comment.