Skip to content

Commit

Permalink
crypto: xilinx: Add upstreamed SHA driver
Browse files Browse the repository at this point in the history
This patch adds the upstreamed ZU+ SHA driver as zynqmp-sha.c. The current
driver is renamed as zynqmp-sha-deprecated.c and it will be maintained for
two releases and then deprecated. By default the old driver will be built.
An option is added in Kconfig to select the new driver if required. The
Kconfig and Makefile is also modified to reflect this update.

Signed-off-by: Harsha <[email protected]>
State: upstream (7ecc3e3, 7a70d9a)
  • Loading branch information
Harsha authored and Michal Simek committed Mar 25, 2022
1 parent 04b085d commit 553716b
Show file tree
Hide file tree
Showing 6 changed files with 488 additions and 213 deletions.
1 change: 0 additions & 1 deletion arch/arm64/configs/xilinx_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,6 @@ CONFIG_NLS_ISO8859_1=y
CONFIG_CRYPTO_CRCT10DIF=y
CONFIG_CRYPTO_USER_API_HASH=y
CONFIG_CRYPTO_USER_API_SKCIPHER=y
CONFIG_CRYPTO_DEV_ZYNQMP_SHA3=y
CONFIG_CRYPTO_DEV_XILINX_RSA=y
CONFIG_CRYPTO_DEV_ZYNQMP_AES_SKCIPHER=y
# CONFIG_XZ_DEC_X86 is not set
Expand Down
1 change: 0 additions & 1 deletion arch/arm64/configs/xilinx_zynqmp_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,6 @@ CONFIG_NLS_ISO8859_1=y
CONFIG_CRYPTO_CRCT10DIF=y
CONFIG_CRYPTO_USER_API_HASH=y
CONFIG_CRYPTO_USER_API_SKCIPHER=y
CONFIG_CRYPTO_DEV_ZYNQMP_SHA3=y
CONFIG_CRYPTO_DEV_XILINX_RSA=y
CONFIG_CRYPTO_DEV_ZYNQMP_AES_SKCIPHER=y
CONFIG_DMA_CMA=y
Expand Down
14 changes: 13 additions & 1 deletion drivers/crypto/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -785,7 +785,19 @@ config CRYPTO_DEV_ROCKCHIP
Supporting cbc/ecb chainmode, and aes/des/des3_ede cipher mode.

config CRYPTO_DEV_ZYNQMP_SHA3
tristate "Support for Xilinx ZynqMP SHA3 hw accelerator"
tristate "Support for Xilinx ZynqMP SHA3 hardware accelerator"
depends on ZYNQMP_FIRMWARE || COMPILE_TEST
depends on !CRYPTO_DEV_ZYNQMP_KECCAK_384
select CRYPTO_SHA3
help
Xilinx ZynqMP has SHA3 engine used for secure hash calculation.
This driver interfaces with SHA3 hardware engine.
Select this if you want to use the ZynqMP module
for SHA3 hash computation.

config CRYPTO_DEV_ZYNQMP_KECCAK_384
bool "Support for Xilinx ZynqMP SHA3 hw accelerator(ahash)"
default y
depends on ARCH_ZYNQMP
select CRYPTO_HASH
help
Expand Down
1 change: 1 addition & 0 deletions drivers/crypto/xilinx/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_CRYPTO_DEV_ZYNQMP_AES) += zynqmp-aes-gcm.o
obj-$(CONFIG_CRYPTO_DEV_ZYNQMP_AES_SKCIPHER) += zynqmp-aes.o
obj-$(CONFIG_CRYPTO_DEV_ZYNQMP_KECCAK_384) += zynqmp-sha-deprecated.o
obj-$(CONFIG_CRYPTO_DEV_ZYNQMP_SHA3) += zynqmp-sha.o
obj-$(CONFIG_CRYPTO_DEV_XILINX_RSA) += zynqmp-rsa.o
295 changes: 295 additions & 0 deletions drivers/crypto/xilinx/zynqmp-sha-deprecated.c
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>");
Loading

0 comments on commit 553716b

Please sign in to comment.