Skip to content
Permalink
Browse files
crypto: zynqmp-sha: Adopted SHA3 support for ZynqMP Soc
This patch adds SHA3 support for ZynqMP Soc.

Signed-off-by: Nava kishore Manne <nava.manne@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
Signed-off-by: Kalyani Akula <kalyani.akula@xilinx.com>
State: pending
[michals:
xilinx: zynqmp-sha: Fix unreachable event
crypto: zynqmp_sha: Make driver thread-safe
v5.15 update
]
  • Loading branch information
Nava kishore Manne authored and Michal Simek committed Feb 1, 2022
1 parent cf5059e commit e2696a07cb200c0ca6be673ba2bc9f3e01384dc6
Show file tree
Hide file tree
Showing 4 changed files with 307 additions and 1 deletion.
@@ -784,6 +784,16 @@ config CRYPTO_DEV_ROCKCHIP
This driver interfaces with the hardware crypto accelerator.
Supporting cbc/ecb chainmode, and aes/des/des3_ede cipher mode.

config CRYPTO_DEV_ZYNQMP_SHA3
tristate "Support for Xilinx ZynqMP SHA3 hw accelerator"
depends on ARCH_ZYNQMP || COMPILE_TEST
select CRYPTO_HASH
help
Xilinx processors have SHA384 engine used for calculation
of hash. This driver interfaces with SHA3 hw accelerator.
Select this if you want to use the ZynqMP module for
Keccak-SHA384 algorithms.

config CRYPTO_DEV_ZYNQMP_AES
tristate "Support for Xilinx ZynqMP AES hw accelerator"
depends on ZYNQMP_FIRMWARE || COMPILE_TEST
@@ -47,7 +47,7 @@ obj-$(CONFIG_CRYPTO_DEV_VMX) += vmx/
obj-$(CONFIG_CRYPTO_DEV_BCM_SPU) += bcm/
obj-$(CONFIG_CRYPTO_DEV_SAFEXCEL) += inside-secure/
obj-$(CONFIG_CRYPTO_DEV_ARTPEC6) += axis/
obj-$(CONFIG_CRYPTO_DEV_ZYNQMP_AES) += xilinx/
obj-y += xilinx/
obj-y += hisilicon/
obj-$(CONFIG_CRYPTO_DEV_AMLOGIC_GXL) += amlogic/
obj-y += keembay/
@@ -1,2 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_CRYPTO_DEV_ZYNQMP_AES) += zynqmp-aes-gcm.o
obj-$(CONFIG_CRYPTO_DEV_ZYNQMP_SHA3) += zynqmp-sha.o
@@ -0,0 +1,295 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2017 Xilinx, Inc.
*/

#include <asm/cacheflush.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/scatterlist.h>
#include <linux/dma-mapping.h>
#include <linux/of_device.h>
#include <linux/crypto.h>
#include <crypto/scatterwalk.h>
#include <crypto/algapi.h>
#include <crypto/sha1.h>
#include <crypto/sha2.h>
#include <crypto/hash.h>
#include <crypto/internal/hash.h>
#include <linux/firmware/xlnx-zynqmp.h>
#include <linux/mutex.h>

#define ZYNQMP_SHA3_INIT 1
#define ZYNQMP_SHA3_UPDATE 2
#define ZYNQMP_SHA3_FINAL 4

#define ZYNQMP_SHA_QUEUE_LENGTH 1

static struct zynqmp_sha_dev *sha_dd;

/*
* .statesize = sizeof(struct zynqmp_sha_reqctx) must be <= PAGE_SIZE / 8 as
* tested by the ahash_prepare_alg() function.
*/
struct zynqmp_sha_reqctx {
struct zynqmp_sha_dev *dd;
unsigned long flags;
};

struct zynqmp_sha_ctx {
struct zynqmp_sha_dev *dd;
unsigned long flags;
};

struct zynqmp_sha_dev {
struct list_head list;
struct device *dev;
/* the lock protects queue and dev list*/
spinlock_t lock;
int err;

unsigned long flags;
struct crypto_queue queue;
struct ahash_request *req;
};

struct zynqmp_sha_drv {
struct list_head dev_list;
/* the lock protects queue and dev list*/
spinlock_t lock;
/* the hw_engine_mutex makes the driver thread-safe */
struct mutex hw_engine_mutex;
};

static struct zynqmp_sha_drv zynqmp_sha = {
.dev_list = LIST_HEAD_INIT(zynqmp_sha.dev_list),
.lock = __SPIN_LOCK_UNLOCKED(zynqmp_sha.lock),
};

static int zynqmp_sha_init(struct ahash_request *req)
{
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
struct zynqmp_sha_ctx *tctx = crypto_ahash_ctx(tfm);
struct zynqmp_sha_reqctx *ctx = ahash_request_ctx(req);
struct zynqmp_sha_dev *dd = sha_dd;
int ret;

spin_lock_bh(&zynqmp_sha.lock);
if (!tctx->dd)
tctx->dd = dd;
else
dd = tctx->dd;

spin_unlock_bh(&zynqmp_sha.lock);

ctx->dd = dd;
dev_dbg(dd->dev, "init: digest size: %d\n",
crypto_ahash_digestsize(tfm));

ret = mutex_lock_interruptible(&zynqmp_sha.hw_engine_mutex);
if (ret)
goto end;

ret = zynqmp_pm_sha_hash(0, 0, ZYNQMP_SHA3_INIT);

end:
return ret;
}

static int zynqmp_sha_update(struct ahash_request *req)
{
struct zynqmp_sha_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
struct zynqmp_sha_dev *dd = tctx->dd;
char *kbuf;
size_t dma_size = req->nbytes;
dma_addr_t dma_addr;
int ret;

if (!req->nbytes)
return 0;

kbuf = dma_alloc_coherent(dd->dev, dma_size, &dma_addr, GFP_KERNEL);
if (!kbuf)
return -ENOMEM;

scatterwalk_map_and_copy(kbuf, req->src, 0, req->nbytes, 0);
caches_clean_inval_user_pou((unsigned long)kbuf,
(unsigned long)kbuf + dma_size);
ret = zynqmp_pm_sha_hash(dma_addr, req->nbytes, ZYNQMP_SHA3_UPDATE);
if (ret) {
mutex_unlock(&zynqmp_sha.hw_engine_mutex);
goto end;
}

dma_free_coherent(dd->dev, dma_size, kbuf, dma_addr);

end:
return ret;
}

static int zynqmp_sha_final(struct ahash_request *req)
{
struct zynqmp_sha_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
struct zynqmp_sha_dev *dd = tctx->dd;
char *kbuf;
size_t dma_size = SHA384_DIGEST_SIZE;
dma_addr_t dma_addr;
int ret;

kbuf = dma_alloc_coherent(dd->dev, dma_size, &dma_addr, GFP_KERNEL);
if (!kbuf)
return -ENOMEM;

ret = zynqmp_pm_sha_hash(dma_addr, dma_size, ZYNQMP_SHA3_FINAL);
memcpy(req->result, kbuf, 48);
dma_free_coherent(dd->dev, dma_size, kbuf, dma_addr);

mutex_unlock(&zynqmp_sha.hw_engine_mutex);
return ret;
}

static int zynqmp_sha_finup(struct ahash_request *req)
{
zynqmp_sha_update(req);
zynqmp_sha_final(req);

return 0;
}

static int zynqmp_sha_digest(struct ahash_request *req)
{
zynqmp_sha_init(req);
zynqmp_sha_update(req);
zynqmp_sha_final(req);

return 0;
}

static int zynqmp_sha_export(struct ahash_request *req, void *out)
{
const struct zynqmp_sha_reqctx *ctx = ahash_request_ctx(req);

memcpy(out, ctx, sizeof(*ctx));
return 0;
}

static int zynqmp_sha_import(struct ahash_request *req, const void *in)
{
struct zynqmp_sha_reqctx *ctx = ahash_request_ctx(req);

memcpy(ctx, in, sizeof(*ctx));
return 0;
}

static int zynqmp_sha_cra_init(struct crypto_tfm *tfm)
{
crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
sizeof(struct zynqmp_sha_reqctx));

return 0;
}

static struct ahash_alg sha3_alg = {
.init = zynqmp_sha_init,
.update = zynqmp_sha_update,
.final = zynqmp_sha_final,
.finup = zynqmp_sha_finup,
.digest = zynqmp_sha_digest,
.export = zynqmp_sha_export,
.import = zynqmp_sha_import,
.halg = {
.digestsize = SHA384_DIGEST_SIZE,
.statesize = sizeof(struct sha256_state),
.base = {
.cra_name = "xilinx-keccak-384",
.cra_driver_name = "zynqmp-keccak-384",
.cra_priority = 300,
.cra_flags = CRYPTO_ALG_ASYNC,
.cra_blocksize = SHA384_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct zynqmp_sha_ctx),
.cra_alignmask = 0,
.cra_module = THIS_MODULE,
.cra_init = zynqmp_sha_cra_init,
}
}
};

static const struct of_device_id zynqmp_sha_dt_ids[] = {
{ .compatible = "xlnx,zynqmp-keccak-384" },
{ /* sentinel */ }
};

MODULE_DEVICE_TABLE(of, zynqmp_sha_dt_ids);

static int zynqmp_sha_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
int err;

sha_dd = devm_kzalloc(&pdev->dev, sizeof(*sha_dd), GFP_KERNEL);
if (!sha_dd)
return -ENOMEM;

sha_dd->dev = dev;
platform_set_drvdata(pdev, sha_dd);
INIT_LIST_HEAD(&sha_dd->list);
spin_lock_init(&sha_dd->lock);
mutex_init(&zynqmp_sha.hw_engine_mutex);
crypto_init_queue(&sha_dd->queue, ZYNQMP_SHA_QUEUE_LENGTH);
spin_lock(&zynqmp_sha.lock);
list_add_tail(&sha_dd->list, &zynqmp_sha.dev_list);
spin_unlock(&zynqmp_sha.lock);

err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
if (err < 0)
dev_err(dev, "no usable DMA configuration");

err = crypto_register_ahash(&sha3_alg);
if (err)
goto err_algs;

return 0;

err_algs:
spin_lock(&zynqmp_sha.lock);
list_del(&sha_dd->list);
spin_unlock(&zynqmp_sha.lock);
dev_err(dev, "initialization failed.\n");

return err;
}

static int zynqmp_sha_remove(struct platform_device *pdev)
{
sha_dd = platform_get_drvdata(pdev);

if (!sha_dd)
return -ENODEV;

spin_lock(&zynqmp_sha.lock);
list_del(&sha_dd->list);
spin_unlock(&zynqmp_sha.lock);

crypto_unregister_ahash(&sha3_alg);

return 0;
}

static struct platform_driver zynqmp_sha_driver = {
.probe = zynqmp_sha_probe,
.remove = zynqmp_sha_remove,
.driver = {
.name = "zynqmp-keccak-384",
.of_match_table = of_match_ptr(zynqmp_sha_dt_ids),
},
};

module_platform_driver(zynqmp_sha_driver);

MODULE_DESCRIPTION("ZynqMP SHA3 hw acceleration support.");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Nava kishore Manne <navam@xilinx.com>");

0 comments on commit e2696a0

Please sign in to comment.