Re: [PATCH v8 1/6] Add SPAcc Skcipher support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Sep 05, 2024 at 05:00:45PM +0530, Pavitrakumar M wrote:
> Add SPAcc Skcipher support to Synopsys Protocol Accelerator(SPAcc) IP,
> which is a crypto accelerator engine.
> SPAcc supports ciphers, hashes and AEAD algorithms such as
> AES in different modes, SHA variants, AES-GCM, Chacha-poly1305 etc.
> 
> Signed-off-by: Bhoomika K <bhoomikak@xxxxxxxxxxxxxxx>
> Signed-off-by: Pavitrakumar M <pavitrakumarm@xxxxxxxxxxxxxxx>
> Acked-by: Ruud Derwig <Ruud.Derwig@xxxxxxxxxxxx>
> ---
>  drivers/crypto/dwc-spacc/spacc_core.c      | 1130 ++++++++++++++++++++
>  drivers/crypto/dwc-spacc/spacc_core.h      |  819 ++++++++++++++
>  drivers/crypto/dwc-spacc/spacc_device.c    |  304 ++++++
>  drivers/crypto/dwc-spacc/spacc_device.h    |  228 ++++
>  drivers/crypto/dwc-spacc/spacc_hal.c       |  367 +++++++
>  drivers/crypto/dwc-spacc/spacc_hal.h       |  114 ++
>  drivers/crypto/dwc-spacc/spacc_interrupt.c |  317 ++++++
>  drivers/crypto/dwc-spacc/spacc_manager.c   |  658 ++++++++++++
>  drivers/crypto/dwc-spacc/spacc_skcipher.c  |  716 +++++++++++++
>  9 files changed, 4653 insertions(+)
>  create mode 100644 drivers/crypto/dwc-spacc/spacc_core.c
>  create mode 100644 drivers/crypto/dwc-spacc/spacc_core.h
>  create mode 100644 drivers/crypto/dwc-spacc/spacc_device.c
>  create mode 100644 drivers/crypto/dwc-spacc/spacc_device.h
>  create mode 100644 drivers/crypto/dwc-spacc/spacc_hal.c
>  create mode 100644 drivers/crypto/dwc-spacc/spacc_hal.h
>  create mode 100644 drivers/crypto/dwc-spacc/spacc_interrupt.c
>  create mode 100644 drivers/crypto/dwc-spacc/spacc_manager.c
>  create mode 100644 drivers/crypto/dwc-spacc/spacc_skcipher.c


> diff --git a/drivers/crypto/dwc-spacc/spacc_device.c b/drivers/crypto/dwc-spacc/spacc_device.c
> new file mode 100644
> index 000000000000..b9b6495fb5e3
> --- /dev/null
> +++ b/drivers/crypto/dwc-spacc/spacc_device.c
> @@ -0,0 +1,304 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <linux/module.h>
> +#include <linux/interrupt.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/platform_device.h>
> +#include "spacc_device.h"
> +
> +static struct platform_device *spacc_pdev[MAX_DEVICES];

Generally drivers aren't limited to some number of instances (except 1 
perhaps).

> +
> +#define VSPACC_PRIORITY_MAX 15
> +
> +void spacc_cmd_process(struct spacc_device *spacc, int x)
> +{
> +	struct spacc_priv *priv = container_of(spacc, struct spacc_priv, spacc);
> +
> +	/* run tasklet to pop jobs off fifo */
> +	tasklet_schedule(&priv->pop_jobs);
> +}
> +void spacc_stat_process(struct spacc_device *spacc)
> +{
> +	struct spacc_priv *priv = container_of(spacc, struct spacc_priv, spacc);
> +
> +	/* run tasklet to pop jobs off fifo */
> +	tasklet_schedule(&priv->pop_jobs);
> +}
> +

> +static const struct of_device_id snps_spacc_id[] = {
> +	{.compatible = "snps,dwc-spacc" },
> +	{ /*sentinel */        }
> +};
> +
> +MODULE_DEVICE_TABLE(of, snps_spacc_id);

You can move the table to where it is used since you no longer use it in 
spacc_init_device.

> +
> +static int spacc_init_device(struct platform_device *pdev)
> +{
> +	int vspacc_idx = -1;
> +	struct resource *mem;
> +	void __iomem *baseaddr;
> +	struct pdu_info   info;
> +	int vspacc_priority = -1;
> +	struct spacc_priv *priv;
> +	int x = 0, err, oldmode, irq_num;
> +	u64 oldtimer = 100000, timer = 100000;
> +
> +	/* Initialize DDT DMA pools based on this device's resources */
> +	if (pdu_mem_init(&pdev->dev)) {
> +		dev_err(&pdev->dev, "Could not initialize DMA pools\n");
> +		return -ENOMEM;
> +	}
> +
> +	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);

You don't need this as devm_platform_get_and_ioremap_resource() does 
this and more.

> +	if (!mem) {
> +		dev_err(&pdev->dev, "no memory resource for spacc\n");
> +		err = -ENXIO;
> +		goto free_ddt_mem_pool;
> +	}
> +
> +	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv) {
> +		err = -ENOMEM;
> +		goto free_ddt_mem_pool;
> +	}
> +
> +	/* Read spacc priority and index and save inside priv.spacc.config */
> +	if (of_property_read_u32(pdev->dev.of_node, "vspacc-priority",
> +				 &vspacc_priority)) {
> +		dev_err(&pdev->dev, "No virtual spacc priority specified\n");
> +		err = -EINVAL;
> +		goto free_ddt_mem_pool;
> +	}
> +
> +	if (vspacc_priority < 0 && vspacc_priority > VSPACC_PRIORITY_MAX) {
> +		dev_err(&pdev->dev, "Invalid virtual spacc priority\n");
> +		err = -EINVAL;
> +		goto free_ddt_mem_pool;
> +	}
> +	priv->spacc.config.priority = vspacc_priority;
> +
> +	if (of_property_read_u32(pdev->dev.of_node, "vspacc-index",
> +				 &vspacc_idx)) {
> +		dev_err(&pdev->dev, "No virtual spacc index specified\n");

This property was not required in the binding, so why does the driver 
require it?

> +		err = -EINVAL;
> +		goto free_ddt_mem_pool;
> +	}
> +	priv->spacc.config.idx = vspacc_idx;
> +
> +	priv->spacc.config.spacc_endian = of_property_read_bool(
> +				pdev->dev.of_node, "little-endian");

Lack of "little-endian" doesn't equal BE.


> +
> +	priv->spacc.config.oldtimer = oldtimer;
> +
> +	if (of_property_read_u64(pdev->dev.of_node, "spacc-wdtimer", &timer)) {
> +		dev_dbg(&pdev->dev, "No spacc wdtimer specified\n");
> +		dev_dbg(&pdev->dev, "Default wdtimer: (100000)\n");
> +		timer = 100000;
> +	}
> +	priv->spacc.config.timer = timer;
> +
> +	baseaddr = devm_platform_get_and_ioremap_resource(pdev, 0, &mem);

You never use 'mem' that I see, so use devm_platform_ioremap_resource() 
instead.

> +	if (IS_ERR(baseaddr)) {
> +		dev_err(&pdev->dev, "unable to map iomem\n");
> +		err = PTR_ERR(baseaddr);
> +		goto free_ddt_mem_pool;
> +	}
> +
> +	pdu_get_version(baseaddr, &info);
> +
> +	dev_dbg(&pdev->dev, "EPN %04X : virt [%d]\n",
> +				info.spacc_version.project,
> +				info.spacc_version.vspacc_idx);
> +
> +	/* Validate virtual spacc index with vspacc count read from
> +	 * VERSION_EXT.VSPACC_CNT. Thus vspacc count=3, gives valid index 0,1,2
> +	 */
> +	if (vspacc_idx != info.spacc_version.vspacc_idx) {
> +		dev_err(&pdev->dev, "DTS vspacc_idx mismatch read value\n");
> +		err = -EINVAL;
> +		goto free_ddt_mem_pool;
> +	}
> +
> +	if (vspacc_idx < 0 || vspacc_idx > (info.spacc_config.num_vspacc - 1)) {
> +		dev_err(&pdev->dev, "Invalid vspacc index specified\n");
> +		err = -EINVAL;
> +		goto free_ddt_mem_pool;
> +	}
> +
> +	err = spacc_init(baseaddr, &priv->spacc, &info);
> +	if (err != CRYPTO_OK) {
> +		dev_err(&pdev->dev, "Failed to initialize device %d\n", x);
> +		err = -ENXIO;
> +		goto free_ddt_mem_pool;
> +	}
> +
> +	spin_lock_init(&priv->hw_lock);
> +	spacc_irq_glbl_disable(&priv->spacc);
> +	tasklet_init(&priv->pop_jobs, spacc_pop_jobs, (unsigned long)priv);
> +
> +	priv->spacc.dptr = &pdev->dev;
> +	platform_set_drvdata(pdev, priv);
> +
> +	irq_num = platform_get_irq(pdev, 0);
> +	if (irq_num < 0) {
> +		dev_err(&pdev->dev, "no irq resource for spacc\n");
> +		err = -ENXIO;
> +		goto free_ddt_mem_pool;
> +	}
> +
> +	/* Determine configured maximum message length. */
> +	priv->max_msg_len = priv->spacc.config.max_msg_size;
> +
> +	if (devm_request_irq(&pdev->dev, irq_num, spacc_irq_handler,
> +			     IRQF_SHARED, dev_name(&pdev->dev),
> +			     &pdev->dev)) {
> +		dev_err(&pdev->dev, "failed to request IRQ\n");
> +		err = -EBUSY;
> +		goto err_tasklet_kill;
> +	}
> +
> +	priv->spacc.irq_cb_stat = spacc_stat_process;
> +	priv->spacc.irq_cb_cmdx = spacc_cmd_process;
> +	oldmode			= priv->spacc.op_mode;
> +	priv->spacc.op_mode     = SPACC_OP_MODE_IRQ;
> +
> +	spacc_irq_stat_enable(&priv->spacc, 1);
> +	spacc_irq_cmdx_enable(&priv->spacc, 0, 1);
> +	spacc_irq_stat_wd_disable(&priv->spacc);
> +	spacc_irq_glbl_enable(&priv->spacc);
> +
> +
> +#if IS_ENABLED(CONFIG_CRYPTO_DEV_SPACC_AUTODETECT)
> +	err = spacc_autodetect(&priv->spacc);
> +	if (err < 0) {
> +		spacc_irq_glbl_disable(&priv->spacc);
> +		goto err_tasklet_kill;
> +	}
> +#else
> +	err = spacc_static_config(&priv->spacc);
> +	if (err < 0) {
> +		spacc_irq_glbl_disable(&priv->spacc);
> +		goto err_tasklet_kill;
> +	}
> +#endif
> +
> +	priv->spacc.op_mode = oldmode;
> +
> +	if (priv->spacc.op_mode == SPACC_OP_MODE_IRQ) {
> +		priv->spacc.irq_cb_stat = spacc_stat_process;
> +		priv->spacc.irq_cb_cmdx = spacc_cmd_process;
> +
> +		spacc_irq_stat_enable(&priv->spacc, 1);
> +		spacc_irq_cmdx_enable(&priv->spacc, 0, 1);
> +		spacc_irq_glbl_enable(&priv->spacc);
> +	} else {
> +		priv->spacc.irq_cb_stat = spacc_stat_process;
> +		priv->spacc.irq_cb_stat_wd = spacc_stat_process;
> +
> +		spacc_irq_stat_enable(&priv->spacc,
> +				      priv->spacc.config.ideal_stat_level);
> +
> +		spacc_irq_cmdx_disable(&priv->spacc, 0);
> +		spacc_irq_stat_wd_enable(&priv->spacc);
> +		spacc_irq_glbl_enable(&priv->spacc);
> +
> +		/* enable the wd by setting the wd_timer = 100000 */
> +		spacc_set_wd_count(&priv->spacc,
> +				   priv->spacc.config.wd_timer =
> +						priv->spacc.config.timer);
> +	}
> +
> +	/* unlock normal*/
> +	if (priv->spacc.config.is_secure_port) {
> +		u32 t;
> +
> +		t = readl(baseaddr + SPACC_REG_SECURE_CTRL);
> +		t &= ~(1UL << 31);
> +		writel(t, baseaddr + SPACC_REG_SECURE_CTRL);
> +	}
> +
> +	/* unlock device by default */
> +	writel(0, baseaddr + SPACC_REG_SECURE_CTRL);

So writel/readl are always little endian (because PCI is always LE). 
Either you aren't handling endianness or you are using "little-endian" 
to refer to something else besides the registers?

> +
> +	return err;
> +
> +err_tasklet_kill:
> +	tasklet_kill(&priv->pop_jobs);
> +	spacc_fini(&priv->spacc);
> +
> +free_ddt_mem_pool:
> +	pdu_mem_deinit(&pdev->dev);
> +
> +	return err;
> +}
> +
> +static void spacc_unregister_algs(void)
> +{
> +#if IS_ENABLED(CONFIG_CRYPTO_DEV_SPACC_HASH)
> +	spacc_unregister_hash_algs();
> +#endif
> +#if  IS_ENABLED(CONFIG_CRYPTO_DEV_SPACC_AEAD)
> +	spacc_unregister_aead_algs();
> +#endif
> +#if IS_ENABLED(CONFIG_CRYPTO_DEV_SPACC_CIPHER)
> +	spacc_unregister_cipher_algs();
> +#endif
> +}
> +
> +
> +static int spacc_crypto_probe(struct platform_device *pdev)
> +{
> +	int rc;
> +
> +	rc = spacc_init_device(pdev);
> +	if (rc < 0)
> +		goto err;
> +
> +	spacc_pdev[0] = pdev;

You have an array of devices, but always write to index 0?

> +
> +#if IS_ENABLED(CONFIG_CRYPTO_DEV_SPACC_HASH)
> +	rc = probe_hashes(pdev);
> +	if (rc < 0)
> +		goto err;
> +#endif
> +
> +#if IS_ENABLED(CONFIG_CRYPTO_DEV_SPACC_CIPHER)
> +	rc = probe_ciphers(pdev);
> +	if (rc < 0)
> +		goto err;
> +#endif
> +
> +#if IS_ENABLED(CONFIG_CRYPTO_DEV_SPACC_AEAD)
> +	rc = probe_aeads(pdev);
> +	if (rc < 0)
> +		goto err;
> +#endif
> +
> +	return 0;
> +err:
> +	spacc_unregister_algs();
> +
> +	return rc;
> +}
> +
> +static void spacc_crypto_remove(struct platform_device *pdev)
> +{
> +	spacc_unregister_algs();
> +	spacc_remove(pdev);
> +}
> +
> +static struct platform_driver spacc_driver = {
> +	.probe  = spacc_crypto_probe,
> +	.remove = spacc_crypto_remove,
> +	.driver = {
> +		.name  = "spacc",
> +		.of_match_table = snps_spacc_id,
> +		.owner = THIS_MODULE,
> +	},
> +};
> +
> +module_platform_driver(spacc_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Synopsys, Inc.");
> +MODULE_DESCRIPTION("SPAcc Crypto Accelerator Driver");
> diff --git a/drivers/crypto/dwc-spacc/spacc_device.h b/drivers/crypto/dwc-spacc/spacc_device.h
> new file mode 100644
> index 000000000000..2223c3cfcf18
> --- /dev/null
> +++ b/drivers/crypto/dwc-spacc/spacc_device.h
> @@ -0,0 +1,228 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#ifndef SPACC_DEVICE_H_
> +#define SPACC_DEVICE_H_
> +
> +#include <crypto/hash.h>
> +#include <crypto/ctr.h>
> +#include <crypto/internal/aead.h>
> +#include <linux/of.h>
> +#include "spacc_core.h"
> +
> +#define MODE_TAB_AEAD(_name, _ciph, _hash, _hashlen, _ivlen, _blocklen) \
> +	.name = _name, .aead = { .ciph = _ciph, .hash = _hash }, \
> +	.hashlen = _hashlen, .ivlen = _ivlen, .blocklen = _blocklen
> +
> +/* Helper macros for initializing the hash/cipher tables. */
> +#define MODE_TAB_COMMON(_name, _id_name, _blocklen) \
> +	.name = _name, .id = CRYPTO_MODE_##_id_name, .blocklen = _blocklen
> +
> +#define MODE_TAB_HASH(_name, _id_name, _hashlen, _blocklen) \
> +	MODE_TAB_COMMON(_name, _id_name, _blocklen), \
> +	.hashlen = _hashlen, .testlen = _hashlen
> +
> +#define MODE_TAB_CIPH(_name, _id_name, _ivlen, _blocklen) \
> +	MODE_TAB_COMMON(_name, _id_name, _blocklen), \
> +	.ivlen = _ivlen
> +
> +#define MODE_TAB_HASH_XCBC	0x8000
> +
> +#define SPACC_MAX_DIGEST_SIZE	64
> +#define SPACC_MAX_KEY_SIZE	32
> +#define SPACC_MAX_IV_SIZE	16
> +
> +#define SPACC_DMA_ALIGN		4
> +#define SPACC_DMA_BOUNDARY	0x10000
> +
> +#define MAX_DEVICES		2
> +/* flag means the IV is computed from setkey and crypt*/
> +#define SPACC_MANGLE_IV_FLAG	0x8000
> +
> +/* we're doing a CTR mangle (for RFC3686/IPsec)*/
> +#define SPACC_MANGLE_IV_RFC3686	0x0100
> +
> +/* we're doing GCM */
> +#define SPACC_MANGLE_IV_RFC4106	0x0200
> +
> +/* we're doing GMAC */
> +#define SPACC_MANGLE_IV_RFC4543	0x0300
> +
> +/* we're doing CCM */
> +#define SPACC_MANGLE_IV_RFC4309	0x0400
> +
> +/* we're doing SM4 GCM/CCM */
> +#define SPACC_MANGLE_IV_RFC8998	0x0500
> +
> +#define CRYPTO_MODE_AES_CTR_RFC3686 (CRYPTO_MODE_AES_CTR \
> +		| SPACC_MANGLE_IV_FLAG \
> +		| SPACC_MANGLE_IV_RFC3686)
> +#define CRYPTO_MODE_AES_GCM_RFC4106 (CRYPTO_MODE_AES_GCM \
> +		| SPACC_MANGLE_IV_FLAG \
> +		| SPACC_MANGLE_IV_RFC4106)
> +#define CRYPTO_MODE_AES_GCM_RFC4543 (CRYPTO_MODE_AES_GCM \
> +		| SPACC_MANGLE_IV_FLAG \
> +		| SPACC_MANGLE_IV_RFC4543)
> +#define CRYPTO_MODE_AES_CCM_RFC4309 (CRYPTO_MODE_AES_CCM \
> +		| SPACC_MANGLE_IV_FLAG \
> +		| SPACC_MANGLE_IV_RFC4309)
> +#define CRYPTO_MODE_SM4_GCM_RFC8998 (CRYPTO_MODE_SM4_GCM)
> +#define CRYPTO_MODE_SM4_CCM_RFC8998 (CRYPTO_MODE_SM4_CCM)
> +
> +struct spacc_crypto_ctx {
> +	struct device *dev;
> +
> +	spinlock_t lock;
> +	struct list_head jobs;
> +	int handle, mode, auth_size, key_len;
> +	unsigned char *cipher_key;
> +
> +	/*
> +	 * Indicates that the H/W context has been setup and can be used for
> +	 * crypto; otherwise, the software fallback will be used.
> +	 */
> +	bool ctx_valid;
> +	unsigned int flag_ppp;
> +
> +	/* salt used for rfc3686/givencrypt mode */
> +	unsigned char csalt[16];
> +	u8 ipad[128] __aligned(sizeof(u32));
> +	u8 digest_ctx_buf[128] __aligned(sizeof(u32));
> +	u8 tmp_buffer[128] __aligned(sizeof(u32));
> +
> +	/* Save keylen from setkey */
> +	int keylen;
> +	u8  key[256];
> +	int zero_key;
> +	unsigned char *tmp_sgl_buff;
> +	struct scatterlist *tmp_sgl;
> +
> +	union{
> +		struct crypto_ahash      *hash;
> +		struct crypto_aead       *aead;
> +		struct crypto_skcipher   *cipher;
> +	} fb;
> +};
> +
> +struct spacc_crypto_reqctx {
> +	struct pdu_ddt src, dst;
> +	void *digest_buf, *iv_buf;
> +	dma_addr_t digest_dma;
> +	int dst_nents, src_nents, aead_nents, total_nents;
> +	int encrypt_op, mode, single_shot;
> +	unsigned int spacc_cipher_cryptlen, rem_nents;
> +
> +	struct aead_cb_data {
> +		int new_handle;
> +		struct spacc_crypto_ctx    *tctx;
> +		struct spacc_crypto_reqctx *ctx;
> +		struct aead_request        *req;
> +		struct spacc_device        *spacc;
> +	} cb;
> +
> +	struct ahash_cb_data {
> +		int new_handle;
> +		struct spacc_crypto_ctx    *tctx;
> +		struct spacc_crypto_reqctx *ctx;
> +		struct ahash_request       *req;
> +		struct spacc_device        *spacc;
> +	} acb;
> +
> +	struct cipher_cb_data {
> +		int new_handle;
> +		struct spacc_crypto_ctx    *tctx;
> +		struct spacc_crypto_reqctx *ctx;
> +		struct skcipher_request    *req;
> +		struct spacc_device        *spacc;
> +	} ccb;
> +
> +	union {
> +		struct ahash_request hash_req;
> +		struct skcipher_request cipher_req;
> +		struct aead_request aead_req;
> +	} fb;
> +};
> +
> +struct mode_tab {
> +	char name[128];
> +
> +	int valid;
> +
> +	/* mode ID used in hash/cipher mode but not aead*/
> +	int id;
> +
> +	/* ciph/hash mode used in aead */
> +	struct {
> +		int ciph, hash;
> +	} aead;
> +
> +	unsigned int hashlen, ivlen, blocklen, keylen[3];
> +	unsigned int keylen_mask, testlen;
> +	unsigned int chunksize, walksize, min_keysize, max_keysize;
> +
> +	bool sw_fb;
> +
> +	union {
> +		unsigned char hash_test[SPACC_MAX_DIGEST_SIZE];
> +		unsigned char ciph_test[3][2 * SPACC_MAX_IV_SIZE];
> +	};
> +};
> +
> +struct spacc_alg {
> +	struct mode_tab *mode;
> +	unsigned int keylen_mask;
> +
> +	struct device *dev[MAX_DEVICES];
> +
> +	struct list_head list;
> +	struct crypto_alg *calg;
> +	struct crypto_tfm *tfm;
> +
> +	union {
> +		struct ahash_alg hash;
> +		struct aead_alg aead;
> +		struct skcipher_alg skcipher;
> +	} alg;
> +};
> +
> +static inline const struct spacc_alg *spacc_tfm_ahash(struct crypto_tfm *tfm)
> +{
> +	const struct crypto_alg *calg = tfm->__crt_alg;
> +
> +	if ((calg->cra_flags & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_AHASH)
> +		return container_of(calg, struct spacc_alg, alg.hash.halg.base);
> +
> +	return NULL;
> +}
> +
> +static inline const struct spacc_alg *spacc_tfm_skcipher(struct crypto_tfm *tfm)
> +{
> +	const struct crypto_alg *calg = tfm->__crt_alg;
> +
> +	if ((calg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
> +					CRYPTO_ALG_TYPE_SKCIPHER)
> +		return container_of(calg, struct spacc_alg, alg.skcipher.base);
> +
> +	return NULL;
> +}
> +
> +static inline const struct spacc_alg *spacc_tfm_aead(struct crypto_tfm *tfm)
> +{
> +	const struct crypto_alg *calg = tfm->__crt_alg;
> +
> +	if ((calg->cra_flags & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_AEAD)
> +		return container_of(calg, struct spacc_alg, alg.aead.base);
> +
> +	return NULL;
> +}
> +
> +int probe_hashes(struct platform_device *spacc_pdev);
> +int spacc_unregister_hash_algs(void);
> +
> +int probe_aeads(struct platform_device *spacc_pdev);
> +int spacc_unregister_aead_algs(void);
> +
> +int probe_ciphers(struct platform_device *spacc_pdev);
> +int spacc_unregister_cipher_algs(void);
> +
> +irqreturn_t spacc_irq_handler(int irq, void *dev);
> +#endif
> diff --git a/drivers/crypto/dwc-spacc/spacc_hal.c b/drivers/crypto/dwc-spacc/spacc_hal.c
> new file mode 100644
> index 000000000000..0d460c4df542
> --- /dev/null
> +++ b/drivers/crypto/dwc-spacc/spacc_hal.c
> @@ -0,0 +1,367 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <linux/dmapool.h>
> +#include <linux/dma-mapping.h>
> +#include "spacc_hal.h"
> +
> +static struct dma_pool *ddt_pool, *ddt16_pool, *ddt4_pool;
> +static struct device *ddt_device;
> +
> +#define PDU_REG_SPACC_VERSION   0x00180UL
> +#define PDU_REG_SPACC_CONFIG    0x00184UL
> +#define PDU_REG_SPACC_CONFIG2   0x00190UL
> +#define PDU_REG_SPACC_IV_OFFSET 0x00040UL
> +#define PDU_REG_PDU_CONFIG      0x00188UL
> +#define PDU_REG_SECURE_LOCK     0x001C0UL
> +
> +int pdu_get_version(void __iomem *dev, struct pdu_info *inf)
> +{
> +	unsigned long tmp;
> +
> +	if (!inf)
> +		return -1;
> +
> +	memset(inf, 0, sizeof(*inf));
> +	tmp = readl(dev + PDU_REG_SPACC_VERSION);
> +
> +	/* Read the SPAcc version block this tells us the revision,
> +	 * project, and a few other feature bits
> +	 *
> +	 * layout for v6.5+
> +	 */
> +	inf->spacc_version = (struct spacc_version_block) {
> +		.minor      = SPACC_ID_MINOR(tmp),
> +		.major      = SPACC_ID_MAJOR(tmp),
> +		.version    = (SPACC_ID_MAJOR(tmp) << 4) | SPACC_ID_MINOR(tmp),
> +		.qos        = SPACC_ID_QOS(tmp),
> +		.is_spacc   = SPACC_ID_TYPE(tmp) == SPACC_TYPE_SPACCQOS,
> +		.is_pdu     = SPACC_ID_TYPE(tmp) == SPACC_TYPE_PDU,
> +		.aux        = SPACC_ID_AUX(tmp),
> +		.vspacc_idx = SPACC_ID_VIDX(tmp),
> +		.partial    = SPACC_ID_PARTIAL(tmp),
> +		.project    = SPACC_ID_PROJECT(tmp),
> +	};
> +
> +	/* try to autodetect */
> +	writel(0x80000000, dev + PDU_REG_SPACC_IV_OFFSET);
> +
> +	if (readl(dev + PDU_REG_SPACC_IV_OFFSET) == 0x80000000)
> +		inf->spacc_version.ivimport = 1;
> +	else
> +		inf->spacc_version.ivimport = 0;
> +
> +
> +	/* Read the SPAcc config block (v6.5+) which tells us how many
> +	 * contexts there are and context page sizes
> +	 * this register is only available in v6.5 and up
> +	 */
> +	tmp = readl(dev + PDU_REG_SPACC_CONFIG);
> +	inf->spacc_config = (struct spacc_config_block) {
> +		SPACC_CFG_CTX_CNT(tmp),
> +		SPACC_CFG_VSPACC_CNT(tmp),
> +		SPACC_CFG_CIPH_CTX_SZ(tmp),
> +		SPACC_CFG_HASH_CTX_SZ(tmp),
> +		SPACC_CFG_DMA_TYPE(tmp),
> +		0, 0, 0, 0
> +	};
> +
> +	/* CONFIG2 only present in v6.5+ cores */
> +	tmp = readl(dev + PDU_REG_SPACC_CONFIG2);
> +	if (inf->spacc_version.qos) {
> +		inf->spacc_config.cmd0_fifo_depth =
> +				SPACC_CFG_CMD0_FIFO_QOS(tmp);
> +		inf->spacc_config.cmd1_fifo_depth =
> +				SPACC_CFG_CMD1_FIFO(tmp);
> +		inf->spacc_config.cmd2_fifo_depth =
> +				SPACC_CFG_CMD2_FIFO(tmp);
> +		inf->spacc_config.stat_fifo_depth =
> +				SPACC_CFG_STAT_FIFO_QOS(tmp);
> +	} else {
> +		inf->spacc_config.cmd0_fifo_depth =
> +				SPACC_CFG_CMD0_FIFO(tmp);
> +		inf->spacc_config.stat_fifo_depth =
> +				SPACC_CFG_STAT_FIFO(tmp);
> +	}
> +
> +	/* only read PDU config if it's actually a PDU engine */
> +	if (inf->spacc_version.is_pdu) {
> +		tmp = readl(dev + PDU_REG_PDU_CONFIG);
> +		inf->pdu_config = (struct pdu_config_block)
> +			{SPACC_PDU_CFG_MINOR(tmp),
> +			 SPACC_PDU_CFG_MAJOR(tmp)};
> +
> +		/* unlock all cores by default */
> +		writel(0, dev + PDU_REG_SECURE_LOCK);
> +	}
> +
> +	return 0;
> +}
> +
> +void pdu_to_dev(void __iomem *addr_, uint32_t *src, unsigned long nword)
> +{
> +	void __iomem *addr = addr_;
> +
> +	while (nword--) {
> +		writel(*src++, addr);
> +		addr += 4;
> +	}
> +}
> +
> +void pdu_from_dev(u32 *dst, void __iomem *addr_, unsigned long nword)
> +{
> +	void __iomem *addr = addr_;
> +
> +	while (nword--) {
> +		*dst++ = readl(addr);
> +		addr += 4;
> +	}
> +}
> +
> +static void pdu_to_dev_big(void __iomem *addr_, const unsigned char *src,
> +			   unsigned long nword)
> +{
> +	unsigned long v;
> +	void __iomem *addr = addr_;
> +
> +	while (nword--) {
> +		v = 0;
> +		v = (v << 8) | ((unsigned long)*src++);
> +		v = (v << 8) | ((unsigned long)*src++);
> +		v = (v << 8) | ((unsigned long)*src++);
> +		v = (v << 8) | ((unsigned long)*src++);

The kernel has helpers for endian conversion and types that define 
endianness of buffers (e.g. __be32). Use them.

> +		writel(v, addr);
> +		addr += 4;
> +	}
> +}




[Index of Archives]     [Kernel]     [Gnu Classpath]     [Gnu Crypto]     [DM Crypt]     [Netfilter]     [Bugtraq]
  Powered by Linux