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; > + } > +}