summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/crypto/caam/Kconfig5
-rw-r--r--drivers/crypto/caam/Makefile1
-rw-r--r--drivers/crypto/caam/fsl_jr_uio.c265
-rw-r--r--drivers/crypto/caam/fsl_jr_uio.h20
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, &regs);
+ 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