diff options
author | Ruchika Gupta <ruchika.gupta@freescale.com> | 2013-08-30 05:05:43 (GMT) |
---|---|---|
committer | Jose Rivera <German.Rivera@freescale.com> | 2013-11-19 03:59:18 (GMT) |
commit | fb26c23e28c66558c3bbf3a520e225fad9787032 (patch) | |
tree | 075c55eb5b5583608681113d7c7a1a24e4a79bb8 | |
parent | 1454e5494020d5377c5f26343032393afd94d595 (diff) | |
download | linux-fsl-qoriq-fb26c23e28c66558c3bbf3a520e225fad9787032.tar.xz |
crypto/caam : Add UIO driver for Job Ring
Signed-off-by: Ruchika Gupta <ruchika.gupta@freescale.com>
Change-Id: I0fff3899c0cd3278e525a62aaa957ceefef912ea
Reviewed-on: http://git.am.freescale.net:8181/4124
Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com>
Reviewed-by: Alexandru Porosanu <alexandru.porosanu@freescale.com>
Reviewed-by: Jose Rivera <German.Rivera@freescale.com>
-rw-r--r-- | drivers/crypto/caam/Kconfig | 5 | ||||
-rw-r--r-- | drivers/crypto/caam/Makefile | 1 | ||||
-rw-r--r-- | drivers/crypto/caam/fsl_jr_uio.c | 265 | ||||
-rw-r--r-- | drivers/crypto/caam/fsl_jr_uio.h | 20 |
4 files changed, 291 insertions, 0 deletions
diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig index 259b99e..dc99692 100644 --- a/drivers/crypto/caam/Kconfig +++ b/drivers/crypto/caam/Kconfig @@ -138,3 +138,8 @@ config CRYPTO_DEV_FSL_CAAM_DEBUG help Selecting this will enable printing of various debug information in the CAAM driver. + +config CRYPTO_DEV_FSL_CAAM_JR_UIO + tristate "Freescale Job Ring UIO support" + depends on CRYPTO_DEV_FSL_CAAM + default n diff --git a/drivers/crypto/caam/Makefile b/drivers/crypto/caam/Makefile index 5ee06d5..9f47455 100644 --- a/drivers/crypto/caam/Makefile +++ b/drivers/crypto/caam/Makefile @@ -16,3 +16,4 @@ ifeq ($(CONFIG_FSL_QMAN), y) endif obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += caamalg_qi.o +obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_JR_UIO) += fsl_jr_uio.o diff --git a/drivers/crypto/caam/fsl_jr_uio.c b/drivers/crypto/caam/fsl_jr_uio.c new file mode 100644 index 0000000..8be027b --- /dev/null +++ b/drivers/crypto/caam/fsl_jr_uio.c @@ -0,0 +1,265 @@ +/* + * Copyright 2013 Freescale Semiconductor, Inc. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/io.h> +#include <linux/uio_driver.h> +#include <linux/slab.h> +#include <linux/list.h> +#include "regs.h" +#include "fsl_jr_uio.h" + +static const char jr_uio_version[] = "fsl JR UIO driver v1.0"; + +#define NAME_LENGTH 30 +#define JR_INDEX_OFFSET 12 + +static const char uio_device_name[] = "fsl-jr"; +static LIST_HEAD(jr_list); + +struct jr_uio_info { + atomic_t ref; /* exclusive, only one open() at a time */ + struct uio_info uio; + char name[NAME_LENGTH]; +}; + +struct jr_dev { + u32 revision; + u32 index; + u32 irq; + struct caam_job_ring __iomem *global_regs; + struct device *dev; + struct resource res; + struct jr_uio_info info; + struct list_head node; + struct list_head jr_list; +}; + +static int jr_uio_open(struct uio_info *info, struct inode *inode) +{ + struct jr_uio_info *uio_info = container_of(info, + struct jr_uio_info, uio); + + if (!atomic_dec_and_test(&uio_info->ref)) { + pr_err("%s: failing non-exclusive open()\n", uio_info->name); + atomic_inc(&uio_info->ref); + return -EBUSY; + } + + return 0; +} + +static int jr_uio_release(struct uio_info *info, struct inode *inode) +{ + struct jr_uio_info *uio_info = container_of(info, + struct jr_uio_info, uio); + atomic_inc(&uio_info->ref); + + return 0; +} + +static irqreturn_t jr_uio_irq_handler(int irq, struct uio_info *dev_info) +{ + struct jr_dev *jrdev = dev_info->priv; + u32 irqstate; + irqstate = rd_reg32(&jrdev->global_regs->jrintstatus); + if (!irqstate) { + dev_warn(jrdev->dev, "Spurious interrupt received\n"); + return IRQ_NONE; + } + + if (irqstate & JRINT_JR_ERROR) + dev_info(jrdev->dev, "uio job ring error - irqstate: %08x\n", + irqstate); + + /*mask valid interrupts */ + setbits32(&jrdev->global_regs->rconfig_lo, JRCFG_IMSK); + + /* Have valid interrupt at this point, just ACK and trigger */ + wr_reg32(&jrdev->global_regs->jrintstatus, irqstate); + + return IRQ_HANDLED; +} + +static int jr_uio_irqcontrol(struct uio_info *dev_info, int irqon) +{ + struct jr_dev *jrdev = dev_info->priv; + + switch (irqon) { + case SEC_UIO_SIMULATE_IRQ_CMD: + uio_event_notify(dev_info); + break; + case SEC_UIO_ENABLE_IRQ_CMD: + /* Enable Job Ring interrupt */ + clrbits32(&jrdev->global_regs->rconfig_lo, JRCFG_IMSK); + break; + case SEC_UIO_DISABLE_IRQ_CMD: + /* Disable Job Ring interrupt */ + setbits32(&jrdev->global_regs->rconfig_lo, JRCFG_IMSK); + break; + default: + break; + } + return 0; +} + +static int __init jr_uio_init(struct jr_dev *uio_dev) +{ + int ret; + struct jr_uio_info *info; + + info = &uio_dev->info; + atomic_set(&info->ref, 1); + info->uio.version = jr_uio_version; + info->uio.name = uio_dev->info.name; + info->uio.mem[0].name = "JR config space"; + info->uio.mem[0].addr = uio_dev->res.start; + info->uio.mem[0].size = uio_dev->res.end - uio_dev->res.start + 1; + info->uio.mem[0].internal_addr = uio_dev->global_regs; + info->uio.mem[0].memtype = UIO_MEM_PHYS; + info->uio.irq = uio_dev->irq; + info->uio.irq_flags = IRQF_SHARED; + info->uio.handler = jr_uio_irq_handler; + info->uio.irqcontrol = jr_uio_irqcontrol; + info->uio.open = jr_uio_open; + info->uio.release = jr_uio_release; + info->uio.priv = uio_dev; + + ret = uio_register_device(uio_dev->dev, &info->uio); + if (ret) { + pr_err("jr_uio: UIO registration failed\n"); + return ret; + } + + return 0; +} + +static const struct of_device_id jr_ids[] = { + { .compatible = "fsl,sec-v4.0-job-ring", }, + { .compatible = "fsl,sec-v4.4-job-ring", }, + { .compatible = "fsl,sec-v5.0-job-ring", }, + { .compatible = "fsl,sec-v6.0-job-ring", }, + {}, +}; + +static int fsl_jr_probe(struct platform_device *dev) +{ + struct resource regs; + struct jr_dev *jr_dev; + struct device_node *jr_node; + int ret, count = 0; + struct list_head *p; + + jr_node = dev->dev.of_node; + if (!jr_node) { + dev_err(&dev->dev, "Device OF-Node is NULL\n"); + return -EFAULT; + } + + jr_dev = kzalloc(sizeof(struct jr_dev), GFP_KERNEL); + if (!jr_dev) { + dev_err(&dev->dev, "kzalloc failed\n"); + return -ENOMEM; + } + + /* Creat name and index */ + list_for_each(p, &jr_list) { + count++; + } + jr_dev->index = count; + + snprintf(jr_dev->info.name, sizeof(jr_dev->info.name) - 1, + "%s%d", uio_device_name, jr_dev->index); + + jr_dev->dev = &dev->dev; + platform_set_drvdata(dev, jr_dev); + + /* Get the resource from dtb node */ + ret = of_address_to_resource(jr_node, 0, ®s); + if (unlikely(ret < 0)) { + dev_err(&dev->dev, "OF-Address-to-resource Failed\n"); + ret = -EFAULT; + goto abort; + } + + jr_dev->res = regs; + + jr_dev->global_regs = of_iomap(jr_node, 0); + + jr_dev->irq = irq_of_parse_and_map(jr_node, 0); + dev_dbg(jr_dev->dev, "errirq: %d\n", jr_dev->irq); + + /* Register UIO */ + ret = jr_uio_init(jr_dev); + if (ret) { + dev_err(&dev->dev, "UIO init Failed\n"); + goto abort_iounmap; + } + + list_add_tail(&jr_dev->node, &jr_list); + + dev_info(jr_dev->dev, "UIO device full name %s initialized\n", + jr_dev->info.name); + + return 0; + +abort_iounmap: + iounmap(jr_dev->global_regs); +abort: + kfree(jr_dev); + return ret; +} + +static int fsl_jr_remove(struct platform_device *dev) +{ + struct jr_dev *jr_dev = platform_get_drvdata(dev); + + if (!jr_dev) + return 0; + + list_del(&jr_dev->node); + uio_unregister_device(&jr_dev->info.uio); + platform_set_drvdata(dev, NULL); + iounmap(jr_dev->global_regs); + kfree(jr_dev); + + return 0; +} + +static struct platform_driver fsl_jr_driver = { + .driver = { + .name = "fsl-jr-uio", + .owner = THIS_MODULE, + .of_match_table = jr_ids, + }, + .probe = fsl_jr_probe, + .remove = fsl_jr_remove, +}; + +static __init int fsl_jr_init(void) +{ + int ret; + + ret = platform_driver_register(&fsl_jr_driver); + if (unlikely(ret < 0)) + pr_warn(": %s:%hu:%s(): platform_driver_register() = %d\n", + __FILE__, __LINE__, __func__, ret); + + return ret; +} + +static void __exit fsl_jr_exit(void) +{ + platform_driver_unregister(&fsl_jr_driver); +} + +module_init(fsl_jr_init); +module_exit(fsl_jr_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ruchika Gupta <ruchika.gupta@freescale.com>"); +MODULE_DESCRIPTION("FSL SEC UIO Driver"); diff --git a/drivers/crypto/caam/fsl_jr_uio.h b/drivers/crypto/caam/fsl_jr_uio.h new file mode 100644 index 0000000..2c4b7c4 --- /dev/null +++ b/drivers/crypto/caam/fsl_jr_uio.h @@ -0,0 +1,20 @@ +/* + * CAAM Job RING UIO support header file + * + * Copyright 2013 Freescale Semiconductor, Inc + */ + +#ifndef FSL_JR_UIO_H +#define FSL_JR_UIO_H + +/** UIO command used by user-space driver to request + * disabling IRQs on a certain job ring */ +#define SEC_UIO_DISABLE_IRQ_CMD 0 +/** UIO command used by user-space driver to request + * enabling IRQs on a certain job ring */ +#define SEC_UIO_ENABLE_IRQ_CMD 1 +/** UIO command used by user-space driver to request SEC kernel driver + * to simulate that an IRQ is generated on a certain job ring */ +#define SEC_UIO_SIMULATE_IRQ_CMD 2 + +#endif |