forked from Xilinx/linux-xlnx
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
crypto: xilinx: Add upstreamed SHA driver
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
Showing
6 changed files
with
488 additions
and
213 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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]>"); |
Oops, something went wrong.