crypto: aspeed - Add HACE hash driver

Hash and Crypto Engine (HACE) is designed to accelerate the
throughput of hash data digest, encryption, and decryption.

Basically, HACE can be divided into two independently engines
- Hash Engine and Crypto Engine. This patch aims to add HACE
hash engine driver for hash accelerator.

Signed-off-by: Neal Liu <neal_liu@aspeedtech.com>
Signed-off-by: Johnny Huang <johnny_huang@aspeedtech.com>
Reviewed-by: Dhananjay Phadke <dphadke@linux.microsoft.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
Neal Liu 2022-08-18 11:59:52 +08:00 committed by Herbert Xu
parent efb4b01c1c
commit 108713a713
8 changed files with 1828 additions and 0 deletions

View File

@ -3210,6 +3210,13 @@ S: Maintained
F: Documentation/devicetree/bindings/usb/aspeed,ast2600-udc.yaml
F: drivers/usb/gadget/udc/aspeed_udc.c
ASPEED CRYPTO DRIVER
M: Neal Liu <neal_liu@aspeedtech.com>
L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers)
S: Maintained
F: Documentation/devicetree/bindings/crypto/aspeed,ast2500-hace.yaml
F: drivers/crypto/aspeed/
ASUS NOTEBOOKS AND EEEPC ACPI/WMI EXTRAS DRIVERS
M: Corentin Chary <corentin.chary@gmail.com>
L: acpi4asus-user@lists.sourceforge.net

View File

@ -818,5 +818,6 @@ config CRYPTO_DEV_SA2UL
acceleration for cryptographic algorithms on these devices.
source "drivers/crypto/keembay/Kconfig"
source "drivers/crypto/aspeed/Kconfig"
endif # CRYPTO_HW

View File

@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_CRYPTO_DEV_ALLWINNER) += allwinner/
obj-$(CONFIG_CRYPTO_DEV_ASPEED) += aspeed/
obj-$(CONFIG_CRYPTO_DEV_ATMEL_AES) += atmel-aes.o
obj-$(CONFIG_CRYPTO_DEV_ATMEL_SHA) += atmel-sha.o
obj-$(CONFIG_CRYPTO_DEV_ATMEL_TDES) += atmel-tdes.o

View File

@ -0,0 +1,32 @@
config CRYPTO_DEV_ASPEED
tristate "Support for Aspeed cryptographic engine driver"
depends on ARCH_ASPEED
help
Hash and Crypto Engine (HACE) is designed to accelerate the
throughput of hash data digest, encryption and decryption.
Select y here to have support for the cryptographic driver
available on Aspeed SoC.
config CRYPTO_DEV_ASPEED_DEBUG
bool "Enable Aspeed crypto debug messages"
depends on CRYPTO_DEV_ASPEED
help
Print Aspeed crypto debugging messages if you use this
option to ask for those messages.
Avoid enabling this option for production build to
minimize driver timing.
config CRYPTO_DEV_ASPEED_HACE_HASH
bool "Enable Aspeed Hash & Crypto Engine (HACE) hash"
depends on CRYPTO_DEV_ASPEED
select CRYPTO_ENGINE
select CRYPTO_SHA1
select CRYPTO_SHA256
select CRYPTO_SHA512
select CRYPTO_HMAC
help
Select here to enable Aspeed Hash & Crypto Engine (HACE)
hash driver.
Supports multiple message digest standards, including
SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, and so on.

View File

@ -0,0 +1,6 @@
obj-$(CONFIG_CRYPTO_DEV_ASPEED) += aspeed_crypto.o
aspeed_crypto-objs := aspeed-hace.o \
$(hace-hash-y)
obj-$(CONFIG_CRYPTO_DEV_ASPEED_HACE_HASH) += aspeed-hace-hash.o
hace-hash-$(CONFIG_CRYPTO_DEV_ASPEED_HACE_HASH) := aspeed-hace-hash.o

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,206 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2021 Aspeed Technology Inc.
*/
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include "aspeed-hace.h"
#ifdef CONFIG_CRYPTO_DEV_ASPEED_DEBUG
#define HACE_DBG(d, fmt, ...) \
dev_info((d)->dev, "%s() " fmt, __func__, ##__VA_ARGS__)
#else
#define HACE_DBG(d, fmt, ...) \
dev_dbg((d)->dev, "%s() " fmt, __func__, ##__VA_ARGS__)
#endif
/* HACE interrupt service routine */
static irqreturn_t aspeed_hace_irq(int irq, void *dev)
{
struct aspeed_hace_dev *hace_dev = (struct aspeed_hace_dev *)dev;
struct aspeed_engine_hash *hash_engine = &hace_dev->hash_engine;
u32 sts;
sts = ast_hace_read(hace_dev, ASPEED_HACE_STS);
ast_hace_write(hace_dev, sts, ASPEED_HACE_STS);
HACE_DBG(hace_dev, "irq status: 0x%x\n", sts);
if (sts & HACE_HASH_ISR) {
if (hash_engine->flags & CRYPTO_FLAGS_BUSY)
tasklet_schedule(&hash_engine->done_task);
else
dev_warn(hace_dev->dev, "HASH no active requests.\n");
}
return IRQ_HANDLED;
}
static void aspeed_hace_hash_done_task(unsigned long data)
{
struct aspeed_hace_dev *hace_dev = (struct aspeed_hace_dev *)data;
struct aspeed_engine_hash *hash_engine = &hace_dev->hash_engine;
hash_engine->resume(hace_dev);
}
static void aspeed_hace_register(struct aspeed_hace_dev *hace_dev)
{
#ifdef CONFIG_CRYPTO_DEV_ASPEED_HACE_HASH
aspeed_register_hace_hash_algs(hace_dev);
#endif
}
static void aspeed_hace_unregister(struct aspeed_hace_dev *hace_dev)
{
#ifdef CONFIG_CRYPTO_DEV_ASPEED_HACE_HASH
aspeed_unregister_hace_hash_algs(hace_dev);
#endif
}
static const struct of_device_id aspeed_hace_of_matches[] = {
{ .compatible = "aspeed,ast2500-hace", .data = (void *)5, },
{ .compatible = "aspeed,ast2600-hace", .data = (void *)6, },
{},
};
static int aspeed_hace_probe(struct platform_device *pdev)
{
const struct of_device_id *hace_dev_id;
struct aspeed_engine_hash *hash_engine;
struct aspeed_hace_dev *hace_dev;
struct resource *res;
int rc;
hace_dev = devm_kzalloc(&pdev->dev, sizeof(struct aspeed_hace_dev),
GFP_KERNEL);
if (!hace_dev)
return -ENOMEM;
hace_dev_id = of_match_device(aspeed_hace_of_matches, &pdev->dev);
if (!hace_dev_id) {
dev_err(&pdev->dev, "Failed to match hace dev id\n");
return -EINVAL;
}
hace_dev->dev = &pdev->dev;
hace_dev->version = (unsigned long)hace_dev_id->data;
hash_engine = &hace_dev->hash_engine;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
platform_set_drvdata(pdev, hace_dev);
hace_dev->regs = devm_ioremap_resource(&pdev->dev, res);
if (!hace_dev->regs) {
dev_err(&pdev->dev, "Failed to map resources\n");
return -ENOMEM;
}
/* Get irq number and register it */
hace_dev->irq = platform_get_irq(pdev, 0);
if (!hace_dev->irq) {
dev_err(&pdev->dev, "Failed to get interrupt\n");
return -ENXIO;
}
rc = devm_request_irq(&pdev->dev, hace_dev->irq, aspeed_hace_irq, 0,
dev_name(&pdev->dev), hace_dev);
if (rc) {
dev_err(&pdev->dev, "Failed to request interrupt\n");
return rc;
}
/* Get clk and enable it */
hace_dev->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(hace_dev->clk)) {
dev_err(&pdev->dev, "Failed to get clk\n");
return -ENODEV;
}
rc = clk_prepare_enable(hace_dev->clk);
if (rc) {
dev_err(&pdev->dev, "Failed to enable clock 0x%x\n", rc);
return rc;
}
/* Initialize crypto hardware engine structure for hash */
hace_dev->crypt_engine_hash = crypto_engine_alloc_init(hace_dev->dev,
true);
if (!hace_dev->crypt_engine_hash) {
rc = -ENOMEM;
goto clk_exit;
}
rc = crypto_engine_start(hace_dev->crypt_engine_hash);
if (rc)
goto err_engine_hash_start;
tasklet_init(&hash_engine->done_task, aspeed_hace_hash_done_task,
(unsigned long)hace_dev);
/* Allocate DMA buffer for hash engine input used */
hash_engine->ahash_src_addr =
dmam_alloc_coherent(&pdev->dev,
ASPEED_HASH_SRC_DMA_BUF_LEN,
&hash_engine->ahash_src_dma_addr,
GFP_KERNEL);
if (!hash_engine->ahash_src_addr) {
dev_err(&pdev->dev, "Failed to allocate dma buffer\n");
rc = -ENOMEM;
goto err_engine_hash_start;
}
aspeed_hace_register(hace_dev);
dev_info(&pdev->dev, "Aspeed Crypto Accelerator successfully registered\n");
return 0;
err_engine_hash_start:
crypto_engine_exit(hace_dev->crypt_engine_hash);
clk_exit:
clk_disable_unprepare(hace_dev->clk);
return rc;
}
static int aspeed_hace_remove(struct platform_device *pdev)
{
struct aspeed_hace_dev *hace_dev = platform_get_drvdata(pdev);
struct aspeed_engine_hash *hash_engine = &hace_dev->hash_engine;
aspeed_hace_unregister(hace_dev);
crypto_engine_exit(hace_dev->crypt_engine_hash);
tasklet_kill(&hash_engine->done_task);
clk_disable_unprepare(hace_dev->clk);
return 0;
}
MODULE_DEVICE_TABLE(of, aspeed_hace_of_matches);
static struct platform_driver aspeed_hace_driver = {
.probe = aspeed_hace_probe,
.remove = aspeed_hace_remove,
.driver = {
.name = KBUILD_MODNAME,
.of_match_table = aspeed_hace_of_matches,
},
};
module_platform_driver(aspeed_hace_driver);
MODULE_AUTHOR("Neal Liu <neal_liu@aspeedtech.com>");
MODULE_DESCRIPTION("Aspeed HACE driver Crypto Accelerator");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,186 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __ASPEED_HACE_H__
#define __ASPEED_HACE_H__
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/fips.h>
#include <linux/dma-mapping.h>
#include <crypto/scatterwalk.h>
#include <crypto/internal/aead.h>
#include <crypto/internal/akcipher.h>
#include <crypto/internal/hash.h>
#include <crypto/internal/kpp.h>
#include <crypto/internal/skcipher.h>
#include <crypto/algapi.h>
#include <crypto/engine.h>
#include <crypto/hmac.h>
#include <crypto/sha1.h>
#include <crypto/sha2.h>
/*****************************
* *
* HACE register definitions *
* *
* ***************************/
#define ASPEED_HACE_STS 0x1C /* HACE Status Register */
#define ASPEED_HACE_HASH_SRC 0x20 /* Hash Data Source Base Address Register */
#define ASPEED_HACE_HASH_DIGEST_BUFF 0x24 /* Hash Digest Write Buffer Base Address Register */
#define ASPEED_HACE_HASH_KEY_BUFF 0x28 /* Hash HMAC Key Buffer Base Address Register */
#define ASPEED_HACE_HASH_DATA_LEN 0x2C /* Hash Data Length Register */
#define ASPEED_HACE_HASH_CMD 0x30 /* Hash Engine Command Register */
/* interrupt status reg */
#define HACE_HASH_ISR BIT(9)
#define HACE_HASH_BUSY BIT(0)
/* hash cmd reg */
#define HASH_CMD_MBUS_REQ_SYNC_EN BIT(20)
#define HASH_CMD_HASH_SRC_SG_CTRL BIT(18)
#define HASH_CMD_SHA512_224 (0x3 << 10)
#define HASH_CMD_SHA512_256 (0x2 << 10)
#define HASH_CMD_SHA384 (0x1 << 10)
#define HASH_CMD_SHA512 (0)
#define HASH_CMD_INT_ENABLE BIT(9)
#define HASH_CMD_HMAC (0x1 << 7)
#define HASH_CMD_ACC_MODE (0x2 << 7)
#define HASH_CMD_HMAC_KEY (0x3 << 7)
#define HASH_CMD_SHA1 (0x2 << 4)
#define HASH_CMD_SHA224 (0x4 << 4)
#define HASH_CMD_SHA256 (0x5 << 4)
#define HASH_CMD_SHA512_SER (0x6 << 4)
#define HASH_CMD_SHA_SWAP (0x2 << 2)
#define HASH_SG_LAST_LIST BIT(31)
#define CRYPTO_FLAGS_BUSY BIT(1)
#define SHA_OP_UPDATE 1
#define SHA_OP_FINAL 2
#define SHA_FLAGS_SHA1 BIT(0)
#define SHA_FLAGS_SHA224 BIT(1)
#define SHA_FLAGS_SHA256 BIT(2)
#define SHA_FLAGS_SHA384 BIT(3)
#define SHA_FLAGS_SHA512 BIT(4)
#define SHA_FLAGS_SHA512_224 BIT(5)
#define SHA_FLAGS_SHA512_256 BIT(6)
#define SHA_FLAGS_HMAC BIT(8)
#define SHA_FLAGS_FINUP BIT(9)
#define SHA_FLAGS_MASK (0xff)
#define ASPEED_CRYPTO_SRC_DMA_BUF_LEN 0xa000
#define ASPEED_CRYPTO_DST_DMA_BUF_LEN 0xa000
#define ASPEED_CRYPTO_GCM_TAG_OFFSET 0x9ff0
#define ASPEED_HASH_SRC_DMA_BUF_LEN 0xa000
#define ASPEED_HASH_QUEUE_LENGTH 50
struct aspeed_hace_dev;
typedef int (*aspeed_hace_fn_t)(struct aspeed_hace_dev *);
struct aspeed_sg_list {
__le32 len;
__le32 phy_addr;
};
struct aspeed_engine_hash {
struct tasklet_struct done_task;
unsigned long flags;
struct ahash_request *req;
/* input buffer */
void *ahash_src_addr;
dma_addr_t ahash_src_dma_addr;
dma_addr_t src_dma;
dma_addr_t digest_dma;
size_t src_length;
/* callback func */
aspeed_hace_fn_t resume;
aspeed_hace_fn_t dma_prepare;
};
struct aspeed_sha_hmac_ctx {
struct crypto_shash *shash;
u8 ipad[SHA512_BLOCK_SIZE];
u8 opad[SHA512_BLOCK_SIZE];
};
struct aspeed_sham_ctx {
struct crypto_engine_ctx enginectx;
struct aspeed_hace_dev *hace_dev;
unsigned long flags; /* hmac flag */
struct aspeed_sha_hmac_ctx base[0];
};
struct aspeed_sham_reqctx {
unsigned long flags; /* final update flag should no use*/
unsigned long op; /* final or update */
u32 cmd; /* trigger cmd */
/* walk state */
struct scatterlist *src_sg;
int src_nents;
unsigned int offset; /* offset in current sg */
unsigned int total; /* per update length */
size_t digsize;
size_t block_size;
size_t ivsize;
const __be32 *sha_iv;
/* remain data buffer */
u8 buffer[SHA512_BLOCK_SIZE * 2];
dma_addr_t buffer_dma_addr;
size_t bufcnt; /* buffer counter */
/* output buffer */
u8 digest[SHA512_DIGEST_SIZE] __aligned(64);
dma_addr_t digest_dma_addr;
u64 digcnt[2];
};
struct aspeed_hace_dev {
void __iomem *regs;
struct device *dev;
int irq;
struct clk *clk;
unsigned long version;
struct crypto_engine *crypt_engine_hash;
struct aspeed_engine_hash hash_engine;
};
struct aspeed_hace_alg {
struct aspeed_hace_dev *hace_dev;
const char *alg_base;
union {
struct skcipher_alg skcipher;
struct ahash_alg ahash;
} alg;
};
enum aspeed_version {
AST2500_VERSION = 5,
AST2600_VERSION
};
#define ast_hace_write(hace, val, offset) \
writel((val), (hace)->regs + (offset))
#define ast_hace_read(hace, offset) \
readl((hace)->regs + (offset))
void aspeed_register_hace_hash_algs(struct aspeed_hace_dev *hace_dev);
void aspeed_unregister_hace_hash_algs(struct aspeed_hace_dev *hace_dev);
#endif