summaryrefslogtreecommitdiff
path: root/drivers/uio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/uio')
-rw-r--r--drivers/uio/Kconfig26
-rw-r--r--drivers/uio/Makefile4
-rw-r--r--drivers/uio/fsl_dma_uio.c283
-rw-r--r--drivers/uio/fsl_rmu_uio.c253
-rw-r--r--drivers/uio/fsl_sec_uio.c383
-rw-r--r--drivers/uio/fsl_srio_uio.c424
-rw-r--r--drivers/uio/uio.c6
7 files changed, 1378 insertions, 1 deletions
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
index 5295be0..26b86cc 100644
--- a/drivers/uio/Kconfig
+++ b/drivers/uio/Kconfig
@@ -128,4 +128,30 @@ config UIO_PRUSS
To compile this driver as a module, choose M here: the module
will be called uio_pruss.
+config UIO_FSL_SRIO
+ tristate "Freescale Serial RapidIO support"
+ depends on RAPIDIO=n
+ default n
+
+config UIO_FSL_RMU
+ tristate "Freescale RapidIO Message Unit support"
+ depends on RAPIDIO=n
+ default n
+ help
+ UIO driver for the Freescale RapidIO Message Unit and Doorbell.
+ This driver will obtain the RMU nodes from DTB structure, and
+ expose the RMU regiter space to user space.
+
+ If you don't know what to do here, say N.
+
+config UIO_FSL_DMA
+ tristate "Freescale DMA support"
+ depends on FSL_DMA=n
+ default n
+
+config UIO_FSL_SEC
+ tristate "Freescale SEC support"
+ depends on CRYPTO_DEV_FSL_CAAM=n
+ default n
+
endif
diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile
index b354c53..bc221ec 100644
--- a/drivers/uio/Makefile
+++ b/drivers/uio/Makefile
@@ -8,3 +8,7 @@ obj-$(CONFIG_UIO_SERCOS3) += uio_sercos3.o
obj-$(CONFIG_UIO_PCI_GENERIC) += uio_pci_generic.o
obj-$(CONFIG_UIO_NETX) += uio_netx.o
obj-$(CONFIG_UIO_PRUSS) += uio_pruss.o
+obj-$(CONFIG_UIO_FSL_SRIO) += fsl_srio_uio.o
+obj-$(CONFIG_UIO_FSL_RMU) += fsl_rmu_uio.o
+obj-$(CONFIG_UIO_FSL_DMA) += fsl_dma_uio.o
+obj-$(CONFIG_UIO_FSL_SEC) += fsl_sec_uio.o
diff --git a/drivers/uio/fsl_dma_uio.c b/drivers/uio/fsl_dma_uio.c
new file mode 100644
index 0000000..6eeffd2
--- /dev/null
+++ b/drivers/uio/fsl_dma_uio.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright 2011-2013 Freescale Semiconductor, Inc.
+ *
+ * Author: Kai Jiang <Kai.Jiang@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/of_platform.h>
+#include <linux/module.h>
+#include <linux/uio_driver.h>
+#include <linux/list.h>
+#include <linux/io.h>
+
+static const char dma_uio_version[] = "DMA UIO driver v1.0";
+
+#define DMA_SR 0x4 /* DMA Status Regsiter */
+
+struct dma_uio_info {
+ atomic_t ref; /* exclusive, only one open() at a time */
+ struct uio_info uio;
+ char name[20];
+};
+
+struct dma_chan {
+ struct device *dev;
+ struct resource *res;
+ struct dma_uio_info *info;
+ struct list_head list;
+ void __iomem *regs_win;
+ int irq;
+ u32 dma_id;
+ u32 ch_id;
+};
+
+struct fsldma_device {
+ struct platform_device *dev;
+ struct list_head ch_list;
+ u32 dma_id;
+};
+
+static int dma_uio_open(struct uio_info *info, struct inode *inode)
+{
+ struct dma_uio_info *i = container_of(info, struct dma_uio_info, uio);
+ if (!atomic_dec_and_test(&i->ref)) {
+ pr_err("%s: failing non-exclusive open()\n", i->name);
+ atomic_inc(&i->ref);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int dma_uio_release(struct uio_info *info, struct inode *inode)
+{
+ struct dma_uio_info *i = container_of(info, struct dma_uio_info, uio);
+ atomic_inc(&i->ref);
+
+ return 0;
+}
+
+static irqreturn_t dma_uio_irq_handler(int irq, struct uio_info *dev_info)
+{
+ struct dma_chan *dma_ch = dev_info->priv;
+
+ out_be32((u32 *)((u8 *)dma_ch->regs_win + DMA_SR), ~0);
+
+ return IRQ_HANDLED;
+}
+
+static int __init dma_chan_uio_setup(struct dma_chan *dma_ch)
+{
+ int ret;
+ struct dma_uio_info *info;
+
+ info = devm_kzalloc(dma_ch->dev, sizeof(struct dma_uio_info),
+ GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ dma_ch->info = info;
+
+ atomic_set(&info->ref, 1);
+ snprintf(info->name, sizeof(info->name)-1, "dma-uio%d-%d",
+ dma_ch->dma_id, dma_ch->ch_id);
+ info->uio.name = info->name;
+ info->uio.version = dma_uio_version;
+ info->uio.mem[0].name = "dma regs";
+ info->uio.mem[0].addr = dma_ch->res->start;
+ info->uio.mem[0].size = (dma_ch->res->end - dma_ch->res->start + 1 >
+ PAGE_SIZE) ?
+ dma_ch->res->end - dma_ch->res->start + 1 : PAGE_SIZE;
+ info->uio.mem[0].internal_addr = dma_ch->regs_win;
+ info->uio.mem[0].memtype = UIO_MEM_PHYS;
+
+ info->uio.irq = dma_ch->irq;
+ info->uio.irq_flags = IRQF_SHARED;
+ info->uio.handler = dma_uio_irq_handler;
+ info->uio.open = dma_uio_open;
+ info->uio.release = dma_uio_release;
+ info->uio.priv = dma_ch;
+
+ ret = uio_register_device(dma_ch->dev, &info->uio);
+ if (ret) {
+ dev_err(dma_ch->dev, "dma_uio: UIO registration failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int fsl_dma_chan_probe(struct fsldma_device *fdev,
+ struct device_node *node)
+{
+ struct resource regs;
+ struct dma_chan *dma_ch;
+ struct device_node *dma_node;
+ int err;
+ u32 *cell;
+ struct platform_device *dev = fdev->dev;
+
+ dma_node = node;
+ dev_dbg(&dev->dev, "Of-device full name %s\n", dma_node->full_name);
+
+ dma_ch = devm_kzalloc(&dev->dev, sizeof(struct dma_chan), GFP_KERNEL);
+ if (!dma_ch) {
+ dev_err(&dev->dev, "Can't alloc memory for 'dma_ch'\n");
+ return -ENOMEM;
+ }
+
+ cell = (u32 *)of_get_property(dma_node, "cell-index", NULL);
+ if (!cell) {
+ dev_err(&dev->dev, "Can't get property 'cell-index'\n");
+ return -EFAULT;
+ }
+
+ dma_ch->dma_id = fdev->dma_id;
+ dma_ch->ch_id = *cell;
+ dma_ch->dev = &dev->dev;
+
+ err = of_address_to_resource(dma_node, 0, &regs);
+ if (err < 0) {
+ dev_err(&dev->dev, "Can't get property 'reg'\n");
+ return -EFAULT;
+ }
+
+ dma_ch->res = devm_request_mem_region(&dev->dev, regs.start,
+ regs.end + 1 - regs.start, "dma");
+ if (dma_ch->res == NULL) {
+ dev_err(&dev->dev, "devm_request_mem_region failed\n");
+ return -ENOMEM;
+ }
+
+ dev_dbg(&dev->dev, "reg start 0x%016llx, size 0x%016llx.\n",
+ dma_ch->res->start, dma_ch->res->end + 1 -
+ dma_ch->res->start);
+
+ dma_ch->regs_win = devm_ioremap(&dev->dev, dma_ch->res->start,
+ dma_ch->res->end - dma_ch->res->start + 1);
+ if (dma_ch->regs_win == NULL) {
+ dev_err(&dev->dev, "devm_ioremap failed\n");
+ return -EIO;
+ }
+
+ dma_ch->irq = irq_of_parse_and_map(dma_node, 0);
+ dev_dbg(dma_ch->dev, "dma channel irq: %d\n", dma_ch->irq);
+
+ err = dma_chan_uio_setup(dma_ch);
+ if (err < 0) {
+ dev_err(dma_ch->dev, "dma_chan_uio_setup failed\n");
+ return err;
+ }
+
+ list_add_tail(&dma_ch->list, &fdev->ch_list);
+
+ dev_info(&dev->dev, "dma channel %s initialized\n", dma_ch->info->name);
+
+ return 0;
+}
+
+static void fsl_dma_chan_remove(struct dma_chan *dma_ch)
+{
+ uio_unregister_device(&dma_ch->info->uio);
+}
+
+static int fsl_dma_uio_probe(struct platform_device *dev)
+{
+ struct device_node *child;
+ struct fsldma_device *fdev;
+ u32 *cell;
+
+ cell = (u32 *)of_get_property(dev->dev.of_node, "cell-index", NULL);
+ if (!cell) {
+ dev_err(&dev->dev, "Can't get property 'cell-index'\n");
+ return -ENODEV;
+ }
+
+ fdev = devm_kzalloc(&dev->dev, sizeof(struct fsldma_device),
+ GFP_KERNEL);
+ if (!fdev) {
+ dev_err(&dev->dev, "Can't alloc memory for 'fdev''\n");
+ return -ENOMEM;
+ }
+
+ fdev->dma_id = *cell;
+ fdev->dev = dev;
+ INIT_LIST_HEAD(&fdev->ch_list);
+ dev_set_drvdata(&dev->dev, fdev);
+
+ for_each_child_of_node(dev->dev.of_node, child)
+ if (of_device_is_compatible(child, "fsl,eloplus-dma-channel"))
+ fsl_dma_chan_probe(fdev, child);
+
+ return 0;
+}
+
+static int fsl_dma_uio_remove(struct platform_device *dev)
+{
+ struct fsldma_device *fdev;
+ struct dma_chan *dma_ch, *ch_tmp;
+
+ fdev = dev_get_drvdata(&dev->dev);
+ list_for_each_entry_safe(dma_ch, ch_tmp, &fdev->ch_list, list) {
+ list_del(&dma_ch->list);
+ fsl_dma_chan_remove(dma_ch);
+ }
+
+ return 0;
+}
+
+
+static const struct of_device_id fsl_of_dma_match[] = {
+ {
+ .compatible = "fsl,eloplus-dma",
+ },
+ {}
+};
+
+static struct platform_driver fsl_dma_uio_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "fsl-of-dma",
+ .of_match_table = fsl_of_dma_match,
+ },
+ .probe = fsl_dma_uio_probe,
+ .remove = fsl_dma_uio_remove,
+};
+
+static __init int fsl_dma_uio_init(void)
+{
+ int err;
+
+ err = platform_driver_register(&fsl_dma_uio_driver);
+ if (err < 0)
+ pr_warn(
+ ": %s:%hu:%s(): platform_driver_register() = %d\n",
+ __FILE__, __LINE__, __func__, err);
+
+ return err;
+}
+
+static void __exit fsl_dma_uio_exit(void)
+{
+ platform_driver_unregister(&fsl_dma_uio_driver);
+
+ pr_warn("fsl dma uio driver removed\n");
+}
+
+module_init(fsl_dma_uio_init);
+module_exit(fsl_dma_uio_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/uio/fsl_rmu_uio.c b/drivers/uio/fsl_rmu_uio.c
new file mode 100644
index 0000000..22ee854
--- /dev/null
+++ b/drivers/uio/fsl_rmu_uio.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/of_platform.h>
+#include <linux/module.h>
+#include <linux/uio_driver.h>
+#include <linux/list.h>
+#include <linux/io.h>
+
+/* rmu unit ID, based on the unit register off-set */
+#define RMU_UNIT_MSG0 0
+#define RMU_UNIT_MSG1 1
+#define RMU_UNIT_DBELL 4
+
+static const char rmu_uio_version[] = "RMU UIO driver v1.0";
+
+struct rmu_uio_info {
+ atomic_t ref; /* exclusive, only one open() at a time */
+ struct uio_info uio;
+ char name[20];
+};
+
+struct rmu_unit {
+ struct device *dev;
+ struct resource *res;
+ struct rmu_uio_info *info;
+ struct list_head list;
+ void __iomem *regs_win;
+ int irq;
+ u32 unit_id;
+};
+
+struct rmu_device {
+ struct platform_device *pdev;
+ struct list_head unit_list;
+};
+
+static int rmu_uio_open(struct uio_info *info, struct inode *inode)
+{
+ struct rmu_uio_info *i = container_of(info, struct rmu_uio_info, uio);
+ struct rmu_unit *unit = info->priv;
+
+ if (!atomic_dec_and_test(&i->ref)) {
+ dev_err(unit->dev,
+ "%s: failing non-exclusive open()\n", i->name);
+ atomic_inc(&i->ref);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int rmu_uio_release(struct uio_info *info, struct inode *inode)
+{
+ struct rmu_uio_info *i = container_of(info, struct rmu_uio_info, uio);
+
+ atomic_inc(&i->ref);
+
+ return 0;
+}
+
+static int __init rmu_unit_uio_setup(struct rmu_unit *unit)
+{
+ int ret;
+ struct rmu_uio_info *info;
+
+ info = devm_kzalloc(unit->dev, sizeof(struct rmu_uio_info),
+ GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ unit->info = info;
+
+ atomic_set(&info->ref, 1);
+ if (unit->unit_id == RMU_UNIT_DBELL)
+ snprintf(info->name, sizeof(info->name), "rmu-uio-doorbell");
+ else
+ snprintf(info->name, sizeof(info->name), "rmu-uio-msg%d",
+ unit->unit_id);
+
+ info->uio.name = info->name;
+ info->uio.version = rmu_uio_version;
+ info->uio.mem[0].name = "rmu regs";
+ info->uio.mem[0].addr = unit->res->start;
+ info->uio.mem[0].size = resource_size(unit->res);
+ info->uio.mem[0].internal_addr = unit->regs_win;
+ info->uio.mem[0].memtype = UIO_MEM_PHYS;
+ info->uio.open = rmu_uio_open;
+ info->uio.release = rmu_uio_release;
+ info->uio.priv = unit;
+
+ ret = uio_register_device(unit->dev, &info->uio);
+ if (ret) {
+ dev_err(unit->dev, "rmu_uio: UIO registration failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int fsl_rmu_unit_probe(struct rmu_device *rmu_dev,
+ struct device_node *node)
+{
+ struct resource regs;
+ struct rmu_unit *unit;
+ struct device_node *unit_node;
+ int err;
+ struct platform_device *pdev = rmu_dev->pdev;
+
+ unit_node = node;
+ dev_dbg(&pdev->dev, "of-device full name %s\n", unit_node->full_name);
+
+ unit = devm_kzalloc(&pdev->dev, sizeof(struct rmu_unit), GFP_KERNEL);
+ if (!unit) {
+ dev_err(&pdev->dev, "Can't alloc memory for 'rmu_unit'\n");
+ return -ENOMEM;
+ }
+
+ unit->dev = &pdev->dev;
+
+ err = of_address_to_resource(unit_node, 0, &regs);
+ if (err < 0) {
+ dev_err(&pdev->dev, "Can't get property 'reg'\n");
+ return -EFAULT;
+ }
+
+ unit->unit_id = (regs.start >> 8) & 0xf;
+ unit->res = devm_request_mem_region(&pdev->dev, regs.start,
+ resource_size(&regs), "rmu");
+ if (!unit->res) {
+ dev_err(&pdev->dev, "devm_request_mem_region failed\n");
+ return -ENOMEM;
+ }
+
+ dev_dbg(&pdev->dev, "reg start 0x%016llx, size 0x%016llx.\n",
+ unit->res->start, resource_size(unit->res));
+
+ unit->regs_win = devm_ioremap(&pdev->dev, unit->res->start,
+ resource_size(unit->res));
+ if (!unit->regs_win) {
+ dev_err(&pdev->dev, "devm_ioremap failed\n");
+ return -EIO;
+ }
+
+ err = rmu_unit_uio_setup(unit);
+ if (err < 0) {
+ dev_err(unit->dev, "rmu_unit_uio_setup failed\n");
+ return err;
+ }
+
+ list_add_tail(&unit->list, &rmu_dev->unit_list);
+
+ dev_info(&pdev->dev, "rmu unit %s initialized\n", unit->info->name);
+
+ return 0;
+}
+
+static void fsl_rmu_unit_remove(struct rmu_unit *unit)
+{
+ uio_unregister_device(&unit->info->uio);
+}
+
+static int fsl_rmu_uio_probe(struct platform_device *pdev)
+{
+ struct device_node *child;
+ struct rmu_device *rmu_dev;
+
+ rmu_dev = devm_kzalloc(&pdev->dev, sizeof(struct rmu_device),
+ GFP_KERNEL);
+ if (!rmu_dev) {
+ dev_err(&pdev->dev, "Can't alloc memory for 'rmu_dev''\n");
+ return -ENOMEM;
+ }
+
+ rmu_dev->pdev = pdev;
+ INIT_LIST_HEAD(&rmu_dev->unit_list);
+ dev_set_drvdata(&pdev->dev, rmu_dev);
+
+ for_each_child_of_node(pdev->dev.of_node, child)
+ if ((of_device_is_compatible(child, "fsl,srio-msg-unit"))
+ || (of_device_is_compatible(child, "fsl,srio-dbell-unit")))
+ fsl_rmu_unit_probe(rmu_dev, child);
+
+ return 0;
+}
+
+static int fsl_rmu_uio_remove(struct platform_device *pdev)
+{
+ struct rmu_device *rmu_dev;
+ struct rmu_unit *unit, *unit_tmp;
+
+ rmu_dev = dev_get_drvdata(&pdev->dev);
+ list_for_each_entry_safe(unit, unit_tmp,
+ &rmu_dev->unit_list, list) {
+ list_del(&unit->list);
+ fsl_rmu_unit_remove(unit);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id fsl_of_rmu_match[] = {
+ {
+ .compatible = "fsl,srio-rmu",
+ },
+ {}
+};
+
+static struct platform_driver fsl_rmu_uio_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "fsl-of-rmu",
+ .of_match_table = fsl_of_rmu_match,
+ },
+ .probe = fsl_rmu_uio_probe,
+ .remove = fsl_rmu_uio_remove,
+};
+
+static __init int fsl_rmu_uio_init(void)
+{
+ int err;
+
+ err = platform_driver_register(&fsl_rmu_uio_driver);
+ if (err < 0)
+ pr_err("fsl-rmu-uio: failed to register platform driver\n");
+
+ return err;
+}
+
+static void __exit fsl_rmu_uio_exit(void)
+{
+ platform_driver_unregister(&fsl_rmu_uio_driver);
+}
+
+module_init(fsl_rmu_uio_init);
+module_exit(fsl_rmu_uio_exit);
+MODULE_AUTHOR("Liu Gang <Gang.Liu@freescale.com>");
+MODULE_DESCRIPTION("UIO driver for Freescale RMU");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/uio/fsl_sec_uio.c b/drivers/uio/fsl_sec_uio.c
new file mode 100644
index 0000000..295ae06
--- /dev/null
+++ b/drivers/uio/fsl_sec_uio.c
@@ -0,0 +1,383 @@
+/*
+ * Copyright 2012-2013 Freescale Semiconductor, Inc.
+ *
+ * Author: Po Liu <po.liu@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#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>
+
+static const char sec_uio_version[] = "fsl SEC UIO driver v1.0";
+
+#define NAME_LENGTH 30
+#define JR_INDEX_OFFSET 12
+
+static const char uio_device_name[NAME_LENGTH] = "fsl-sec";
+static LIST_HEAD(sec_list);
+
+struct sec_uio_info {
+ atomic_t ref; /* exclusive, only one open() at a time */
+ struct uio_info uio;
+ char name[NAME_LENGTH];
+};
+
+struct sec_dev {
+ u32 revision;
+ u32 index;
+ u32 irq;
+ void __iomem *global_regs;
+ struct device *dev;
+ struct resource res;
+ struct sec_uio_info info;
+ struct list_head node;
+ struct list_head jr_list;
+};
+
+struct sec_job_ring {
+ struct list_head list_node;
+ u32 index;
+ u32 irq;
+ struct device *dev;
+ struct sec_uio_info info;
+ struct resource *res;
+};
+
+static int sec_uio_open(struct uio_info *info, struct inode *inode)
+{
+ struct sec_uio_info *uio_info = container_of(info,
+ struct sec_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 sec_uio_release(struct uio_info *info, struct inode *inode)
+{
+ struct sec_uio_info *uio_info = container_of(info,
+ struct sec_uio_info, uio);
+ atomic_inc(&uio_info->ref);
+
+ return 0;
+}
+
+static irqreturn_t sec_uio_irq_handler(int irq, struct uio_info *dev_info)
+{
+ return IRQ_NONE;
+}
+
+static int sec_uio_irqcontrol(struct uio_info *dev_info, int irqon)
+{
+ return 0;
+}
+
+static irqreturn_t sec_jr_irq_handler(int irq, struct uio_info *dev_info)
+{
+ return IRQ_NONE;
+}
+
+static int sec_jr_irqcontrol(struct uio_info *dev_info, int irqon)
+{
+ return 0;
+}
+
+static int __init sec_uio_init(struct sec_dev *uio_dev)
+{
+ int ret;
+ struct sec_uio_info *info;
+
+ info = &uio_dev->info;
+ atomic_set(&info->ref, 1);
+ info->uio.version = sec_uio_version;
+ info->uio.name = uio_dev->info.name;
+ info->uio.mem[0].name = "sec 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 = sec_uio_irq_handler;
+ info->uio.irqcontrol = sec_uio_irqcontrol;
+ info->uio.open = sec_uio_open;
+ info->uio.release = sec_uio_release;
+ info->uio.priv = uio_dev;
+
+ ret = uio_register_device(uio_dev->dev, &info->uio);
+ if (ret) {
+ pr_err("sec_uio: UIO registration failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __init sec_jr_uio_init(struct sec_job_ring *jr)
+{
+ int ret;
+ struct sec_uio_info *info;
+
+ info = &jr->info;
+ atomic_set(&info->ref, 1);
+ info->uio.version = sec_uio_version;
+ info->uio.name = jr->info.name;
+ info->uio.mem[0].name = "sec job ring";
+ info->uio.mem[0].addr = jr->res->start;
+ info->uio.mem[0].size = jr->res->end - jr->res->start + 1;
+ info->uio.mem[0].memtype = UIO_MEM_PHYS;
+ info->uio.irq = jr->irq;
+ info->uio.irq_flags = IRQF_SHARED;
+ info->uio.handler = sec_jr_irq_handler;
+ info->uio.irqcontrol = sec_jr_irqcontrol;
+ info->uio.open = sec_uio_open;
+ info->uio.release = sec_uio_release;
+ info->uio.priv = jr;
+
+ ret = uio_register_device(jr->dev, &info->uio);
+ if (ret) {
+ pr_err("sec_jr_uio: UIO registration failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int fsl_sec_jr_probe(struct device_node *jr_node,
+ struct sec_dev *scdev)
+{
+ struct sec_job_ring *jr;
+ struct resource regs;
+ int ret;
+
+ if (!jr_node || !scdev)
+ return -EINVAL;
+
+ jr = kzalloc(sizeof(*jr), GFP_KERNEL);
+ if (!jr) {
+ dev_err(scdev->dev, "Can't alloc memory for job ring\n");
+ return -ENOMEM;
+ }
+
+ jr->dev = scdev->dev;
+
+ ret = of_address_to_resource(jr_node, 0, &regs);
+ if (unlikely(ret < 0)) {
+ dev_err(jr->dev, "Can't get property 'reg'\n");
+ ret = -EFAULT;
+ goto abort_jr;
+ }
+
+ jr->index = (regs.start >> JR_INDEX_OFFSET) & 0xf;
+ snprintf(jr->info.name, sizeof(jr->info.name)-1,
+ "sec_job_ring%d-%d", scdev->index, jr->index);
+
+ jr->res = devm_request_mem_region(scdev->dev, regs.start,
+ regs.end + 1 - regs.start,
+ jr->info.name);
+ if (unlikely(!jr->res)) {
+ dev_err(jr->dev, "devm_request_mem_region failed\n");
+ ret = -ENOMEM;
+ goto abort_jr;
+ }
+
+ dev_dbg(jr->dev,
+ "sec_job_ring%d-%d reg start 0x%016llx, size 0x%016llx.\n",
+ scdev->index, jr->index, jr->res->start,
+ jr->res->end + 1 - jr->res->start);
+
+ jr->irq = irq_of_parse_and_map(jr_node, 0);
+ dev_dbg(jr->dev, "errirq: %d\n", jr->irq);
+
+ ret = sec_jr_uio_init(jr);
+ if (ret)
+ goto abort_jr;
+
+ list_add(&jr->list_node, &scdev->jr_list);
+ dev_info(jr->dev, "sec_job_ring%d-%d initialized.\n",
+ scdev->index, jr->index);
+
+ return 0;
+abort_jr:
+ kfree(jr);
+ return ret;
+}
+
+static int fsl_sec_jr_remove(struct sec_job_ring *jr)
+{
+ if (!jr)
+ return 0;
+ uio_unregister_device(&jr->info.uio);
+ kfree(jr);
+
+ 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_sec_probe(struct platform_device *dev)
+{
+ struct resource regs;
+ struct sec_dev *sec_dev;
+ struct device_node *sec_node, *child;
+ struct sec_job_ring *jr, *tmp;
+ int ret, count = 0;
+ struct list_head *p;
+
+ sec_node = dev->dev.of_node;
+ if (!sec_node) {
+ dev_err(&dev->dev, "Device OF-Node is NULL");
+ return -EFAULT;
+ }
+
+ sec_dev = kzalloc(sizeof(struct sec_dev), GFP_KERNEL);
+ if (!sec_dev)
+ return -ENOMEM;
+
+ /* Creat name and index */
+ list_for_each(p, &sec_list) {
+ count++;
+ }
+ sec_dev->index = count;
+
+ snprintf(sec_dev->info.name, sizeof(sec_dev->info.name) - 1,
+ "%s%d", uio_device_name, sec_dev->index);
+
+ sec_dev->dev = &dev->dev;
+ platform_set_drvdata(dev, sec_dev);
+
+ dev_info(sec_dev->dev, "UIO device full name %s initialized\n",
+ sec_dev->info.name);
+
+ /* Create each jr under this sec node */
+ INIT_LIST_HEAD(&sec_dev->jr_list);
+ for_each_child_of_node(sec_node, child) {
+ if (of_match_node(jr_ids, child))
+ fsl_sec_jr_probe(child, sec_dev);
+ }
+
+ /* Get the resource from dtb node */
+ ret = of_address_to_resource(sec_node, 0, &regs);
+ if (unlikely(ret < 0)) {
+ ret = -EFAULT;
+ goto abort;
+ }
+
+ sec_dev->res = regs;
+
+ sec_dev->global_regs = of_iomap(sec_node, 0);
+
+ sec_dev->irq = irq_of_parse_and_map(sec_node, 0);
+ dev_dbg(sec_dev->dev, "errirq: %d\n", sec_dev->irq);
+
+ /* Register UIO */
+ ret = sec_uio_init(sec_dev);
+ if (ret)
+ goto abort_iounmap;
+
+ list_add_tail(&sec_dev->node, &sec_list);
+
+ return 0;
+
+abort_iounmap:
+ iounmap(sec_dev->global_regs);
+abort:
+ list_for_each_entry_safe(jr, tmp, &sec_dev->jr_list, list_node) {
+ list_del(&jr->list_node);
+ fsl_sec_jr_remove(jr);
+ }
+ kfree(sec_dev);
+ return ret;
+}
+
+static int fsl_sec_remove(struct platform_device *dev)
+{
+ struct sec_dev *sec_dev = platform_get_drvdata(dev);
+ struct sec_job_ring *jr, *tmp;
+
+ if (!sec_dev)
+ return 0;
+
+ list_for_each_entry_safe(jr, tmp, &sec_dev->jr_list, list_node) {
+ list_del(&jr->list_node);
+ fsl_sec_jr_remove(jr);
+ }
+
+ list_del(&sec_dev->node);
+ uio_unregister_device(&sec_dev->info.uio);
+ platform_set_drvdata(dev, NULL);
+ iounmap(sec_dev->global_regs);
+ kfree(sec_dev);
+
+ return 0;
+}
+
+static const struct of_device_id sec_ids[] = {
+ { .compatible = "fsl,sec-v4.0", },
+ { .compatible = "fsl,sec-v4.4", },
+ { .compatible = "fsl,sec-v5.0", },
+ { .compatible = "fsl,sec-v6.0", },
+ {},
+};
+
+static struct platform_driver fsl_sec_driver = {
+ .driver = {
+ .name = "fsl-sec-uio",
+ .owner = THIS_MODULE,
+ .of_match_table = sec_ids,
+ },
+ .probe = fsl_sec_probe,
+ .remove = fsl_sec_remove,
+};
+
+static __init int fsl_sec_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&fsl_sec_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_sec_exit(void)
+{
+ platform_driver_unregister(&fsl_sec_driver);
+}
+
+module_init(fsl_sec_init);
+module_exit(fsl_sec_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Liu Po <po.liu@freescale.com>");
+MODULE_DESCRIPTION("FSL SEC UIO Driver");
diff --git a/drivers/uio/fsl_srio_uio.c b/drivers/uio/fsl_srio_uio.c
new file mode 100644
index 0000000..23e799d
--- /dev/null
+++ b/drivers/uio/fsl_srio_uio.c
@@ -0,0 +1,424 @@
+/*
+ * Copyright 2011-2013 Freescale Semiconductor, Inc.
+ *
+ * Author: Kai Jiang <Kai.Jiang@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/uio_driver.h>
+#include <linux/list.h>
+
+#define EPWISR 0x10010 /* Error/Port-Write Interrupt Status */
+#define IECSR 0x10130 /* Port Implementation Err Cmd & Status */
+#define ESCSR 0x00158 /* Port Error and Status Cmd & Status */
+#define EDCSR 0x00640 /* Port Error Detect Cmd & Status */
+#define LTLEDCSR 0x00608 /* Logical/Transport Layer Err Detect Cmd & Status */
+#define LTLEECSR 0x0060c /* Logical/Transport Layer Err Enable Cmd & Status */
+#define SRIO_ESCSR_CLEAR 0x07120204
+#define SRIO_IECSR_CLEAR 0x80000000
+
+struct srio_uio_info {
+ atomic_t ref;
+ struct uio_info uio;
+ char name[20];
+};
+
+struct srio_port_info {
+ struct device *dev;
+ struct srio_uio_info *info;
+ struct resource *res;
+ struct list_head list;
+ u32 port_id;
+};
+
+struct srio_regs_info {
+ struct device *dev;
+ struct srio_uio_info *info;
+ struct resource *res;
+ void __iomem *regs_win;
+};
+
+struct srio_dev {
+ struct device *dev;
+ struct srio_regs_info regs;
+ struct list_head port_list;
+ int irq;
+ u32 port_num;
+};
+
+enum srio_uio_init_type {
+ SRIO_REGS,
+ SRIO_PORT
+};
+
+static const char srio_uio_version[] = "SRIO UIO driver v1.0";
+
+static int srio_uio_open(struct uio_info *info, struct inode *inode)
+{
+ struct srio_uio_info *i = container_of(info, struct srio_uio_info, uio);
+
+ if (atomic_dec_return(&i->ref) < 0) {
+ pr_err("%s: failing open()\n", i->name);
+ atomic_inc(&i->ref);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int srio_uio_release(struct uio_info *info, struct inode *inode)
+{
+ struct srio_uio_info *i = container_of(info, struct srio_uio_info, uio);
+
+ atomic_inc(&i->ref);
+
+ return 0;
+}
+
+static irqreturn_t srio_uio_irq_handler(int irq, struct uio_info *dev_info)
+{
+ struct srio_dev *sriodev = dev_info->priv;
+ int i;
+ unsigned int port_bits, ltledcsr;
+
+ ltledcsr = in_be32(sriodev->regs.regs_win + LTLEDCSR);
+ port_bits = in_be32(sriodev->regs.regs_win + EPWISR);
+
+ if (!port_bits && !ltledcsr)
+ return IRQ_NONE;
+
+ if (ltledcsr)
+ /* Disable logical/transport layer error interrupt */
+ out_be32(sriodev->regs.regs_win + LTLEECSR, 0);
+
+ for (i = 0; i < sriodev->port_num; i++) {
+ if (port_bits & (1 << (31 - i))) {
+ /* Clear retry error threshold exceeded */
+ out_be32(sriodev->regs.regs_win + IECSR + 0x80 * i,
+ SRIO_IECSR_CLEAR);
+ /* Clear ESCSR */
+ out_be32(sriodev->regs.regs_win + ESCSR + 0x20 * i,
+ SRIO_ESCSR_CLEAR);
+ /* Clear EDCSR */
+ out_be32(sriodev->regs.regs_win + EDCSR + 0x40 * i,
+ 0);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int __init srio_uio_setup(struct srio_dev *sriodev, u8 type, u32 port_id)
+{
+ int err;
+ struct srio_uio_info *info;
+ struct srio_port_info *srio_port, *port_tmp;
+
+ info = devm_kzalloc(sriodev->dev, sizeof(struct srio_uio_info),
+ GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ if (type == SRIO_REGS) {
+ atomic_set(&info->ref, sriodev->port_num);
+ sriodev->regs.info = info;
+ snprintf(info->name, sizeof(info->name)-1, "srio-uio-regs");
+ info->uio.name = info->name;
+ info->uio.version = srio_uio_version;
+ info->uio.mem[0].name = "srio regs";
+ info->uio.mem[0].addr = sriodev->regs.res->start;
+ info->uio.mem[0].size = sriodev->regs.res->end -
+ sriodev->regs.res->start + 1;
+ info->uio.mem[0].memtype = UIO_MEM_PHYS;
+ info->uio.irq = sriodev->irq;
+
+ } else if (type == SRIO_PORT) {
+ err = -ENODEV;
+ atomic_set(&info->ref, 1);
+ list_for_each_entry_safe(srio_port, port_tmp,
+ &sriodev->port_list, list) {
+
+ if (srio_port->port_id == port_id) {
+ srio_port->info = info;
+ snprintf(info->name, sizeof(info->name)-1,
+ "srio-uio-port%d", port_id);
+ info->uio.name = info->name;
+ info->uio.version = srio_uio_version;
+ info->uio.mem[0].name = "srio window";
+ info->uio.mem[0].addr = srio_port->res->start;
+ info->uio.mem[0].size = srio_port->res->end -
+ srio_port->res->start + 1;
+ info->uio.mem[0].memtype = UIO_MEM_PHYS;
+ err = 0;
+ break;
+ }
+
+ }
+
+ if (err < 0)
+ return err;
+ } else
+ return -ENODEV;
+
+ info->uio.irq_flags = IRQF_SHARED;
+ info->uio.handler = srio_uio_irq_handler;
+ info->uio.open = srio_uio_open;
+ info->uio.release = srio_uio_release;
+ info->uio.priv = sriodev;
+
+ err = uio_register_device(sriodev->dev, &info->uio);
+ if (err) {
+ dev_err(sriodev->dev, "srio_uio: UIO registration failed\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static int srio_uio_init(struct srio_dev *sriodev)
+{
+ struct srio_port_info *srio_port, *port_tmp;
+ int err;
+
+ srio_uio_setup(sriodev, SRIO_REGS, 0);
+ list_for_each_entry_safe(srio_port, port_tmp,
+ &sriodev->port_list, list) {
+ err = srio_uio_setup(sriodev, SRIO_PORT, srio_port->port_id);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int srio_uio_cleanup(struct srio_dev *sriodev)
+{
+ struct srio_port_info *srio_port, *port_tmp;
+
+ list_for_each_entry_safe(srio_port, port_tmp,
+ &sriodev->port_list, list) {
+ uio_unregister_device(&srio_port->info->uio);
+ list_del(&srio_port->list);
+ }
+
+ uio_unregister_device(&sriodev->regs.info->uio);
+
+ return 0;
+}
+
+static int fsl_srio_port_probe(struct srio_dev *srio_dev,
+ struct device_node *node)
+{
+ struct device_node *srio_node;
+ struct srio_port_info *srio_port;
+ const u32 *dt_range, *cell, *cell_index;
+ u64 law_start, law_size;
+ int paw, aw, sw;
+
+ srio_node = node;
+
+ cell_index = of_get_property(srio_node, "cell-index", NULL);
+ if (!cell_index) {
+ dev_err(srio_dev->dev, "Can't get %s property 'cell-index'\n",
+ srio_node->full_name);
+ return -ENODEV;
+ }
+
+ dt_range = of_get_property(srio_node, "ranges", NULL);
+ if (!dt_range) {
+ dev_err(srio_dev->dev, "Can't get %s property 'ranges'\n",
+ srio_node->full_name);
+ return -ENODEV;
+ }
+
+ /* Get node address wide */
+ cell = of_get_property(srio_node, "#address-cells", NULL);
+ if (!cell) {
+ dev_err(srio_dev->dev,
+ "Can't get %s property '#address-cells'\n",
+ srio_node->full_name);
+ return -ENODEV;
+ }
+ aw = *cell;
+
+ /* Get node size wide */
+ cell = of_get_property(srio_node, "#size-cells", NULL);
+ if (!cell) {
+ dev_err(srio_dev->dev, "Can't get %s property '#size-cells'\n",
+ srio_node->full_name);
+ return -ENODEV;
+ }
+ sw = *cell;
+
+ /* Get parent address wide wide */
+ paw = of_n_addr_cells(srio_node);
+ law_start = of_read_number(dt_range + aw, paw);
+ law_size = of_read_number(dt_range + aw + paw, sw);
+
+ srio_port = devm_kzalloc(srio_dev->dev, sizeof(struct srio_port_info),
+ GFP_KERNEL);
+ srio_port->res = devm_request_mem_region(srio_dev->dev, law_start,
+ law_size, "srio win");
+
+ if (srio_port->res == NULL) {
+ dev_err(srio_dev->dev, "devm_request_mem_region failed\n");
+ return -ENOMEM;
+ }
+
+ dev_dbg(srio_dev->dev, "window start 0x%016llx, size 0x%016llx.\n",
+ srio_port->res->start, srio_port->res->end + 1 -
+ srio_port->res->start);
+
+ srio_port->port_id = *cell_index;
+ srio_port->dev = srio_dev->dev;
+ srio_dev->port_num++;
+ list_add_tail(&srio_port->list, &srio_dev->port_list);
+
+ return 0;
+}
+
+static void fsl_srio_port_remove(struct srio_dev *srio_dev)
+{
+ struct srio_port_info *srio_port, *port_tmp;
+
+ list_for_each_entry_safe(srio_port, port_tmp,
+ &srio_dev->port_list, list)
+ list_del(&srio_port->list);
+}
+
+static int fsl_srio_uio_probe(struct platform_device *dev)
+{
+ struct resource regs;
+ struct srio_dev *srio_dev;
+ struct device_node *srio_node;
+ struct device_node *child;
+ int err;
+
+ srio_node = dev->dev.of_node;
+ dev_dbg(&dev->dev, "Of-device full name %s\n", srio_node->full_name);
+
+ srio_dev = devm_kzalloc(&dev->dev, sizeof(struct srio_dev), GFP_KERNEL);
+ if (!srio_dev) {
+ dev_err(&dev->dev, "Can't alloc memory for 'srio_dev'\n");
+ return -ENOMEM;
+ }
+ srio_dev->dev = &dev->dev;
+ dev_set_drvdata(&dev->dev, srio_dev);
+
+ err = of_address_to_resource(srio_node, 0, &regs);
+ if (err < 0) {
+ dev_err(&dev->dev, "Can't get property 'reg'\n");
+ return -EFAULT;
+ }
+
+ srio_dev->regs.res = devm_request_mem_region(&dev->dev, regs.start,
+ regs.end + 1 - regs.start, "srio regs");
+ if (srio_dev->regs.res == NULL) {
+ dev_err(&dev->dev, "devm_request_mem_region failed\n");
+ return -ENOMEM;
+ }
+
+ dev_dbg(&dev->dev, "reg start 0x%016llx, size 0x%016llx.\n",
+ srio_dev->regs.res->start,
+ srio_dev->regs.res->end + 1 - srio_dev->regs.res->start);
+
+ srio_dev->regs.regs_win = devm_ioremap(&dev->dev,
+ srio_dev->regs.res->start,
+ srio_dev->regs.res->end -
+ srio_dev->regs.res->start + 1);
+ if (srio_dev->regs.regs_win == NULL) {
+ dev_err(&dev->dev, "devm_ioremap failed\n");
+ return -EIO;
+ }
+
+ srio_dev->irq = irq_of_parse_and_map(srio_node, 0);
+ dev_dbg(srio_dev->dev, "err irq: %d\n", srio_dev->irq);
+
+ INIT_LIST_HEAD(&srio_dev->port_list);
+
+ for_each_child_of_node(dev->dev.of_node, child) {
+ err = fsl_srio_port_probe(srio_dev, child);
+ if (err < 0) {
+ fsl_srio_port_remove(srio_dev);
+ return err;
+ }
+ }
+
+ err = srio_uio_init(srio_dev);
+ if (err < 0) {
+ dev_err(srio_dev->dev, "srio_uio_init failed\n");
+ srio_uio_cleanup(srio_dev);
+ return err;
+ }
+
+ dev_info(srio_dev->dev, "Rapidio UIO driver initialized\n");
+
+ return 0;
+}
+
+static int fsl_srio_uio_remove(struct platform_device *dev)
+{
+ struct srio_dev *srio_dev = platform_get_drvdata(dev);
+
+ srio_uio_cleanup(srio_dev);
+
+ return 0;
+}
+
+static const struct of_device_id fsl_srio_uio_match[] = {
+ {
+ .compatible = "fsl,srio",
+ },
+ {}
+};
+
+static struct platform_driver fsl_of_srio_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "fsl-of-srio",
+ .of_match_table = fsl_srio_uio_match,
+ },
+ .probe = fsl_srio_uio_probe,
+ .remove = fsl_srio_uio_remove,
+};
+
+static __init int fsl_srio_uio_init(void)
+{
+ int err;
+
+ err = platform_driver_register(&fsl_of_srio_driver);
+ if (err < 0)
+ pr_warn(
+ ": %s:%hu:%s(): platform_driver_register() = %d\n",
+ __FILE__, __LINE__, __func__, err);
+
+ return err;
+}
+
+static void __exit fsl_srio_uio_exit(void)
+{
+ platform_driver_unregister(&fsl_of_srio_driver);
+
+ pr_warn("fsl srio uio driver removed\n");
+}
+
+module_init(fsl_srio_uio_init);
+module_exit(fsl_srio_uio_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index b645c47..450c4e6 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -643,7 +643,11 @@ static int uio_mmap_physical(struct vm_area_struct *vma)
if (mi < 0)
return -EINVAL;
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ if (idev->info->set_pgprot)
+ vma->vm_page_prot = idev->info->set_pgprot(idev->info, mi,
+ vma->vm_page_prot);
+ else
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
return remap_pfn_range(vma,
vma->vm_start,