From: "Andrew F. Davis" <a...@ti.com>

This dummy test driver lets us do some very basic testing of
importing dma-bufs.

It is based originally on TI's out of tree "DMA-BUF physical
address user-space exporter" originally by
Andrew F. Davis <a...@ti.com>

Cc: Benjamin Gaignard <benjamin.gaign...@linaro.org>
Cc: Sumit Semwal <sumit.sem...@linaro.org>
Cc: Liam Mark <lm...@codeaurora.org>
Cc: Pratik Patel <prat...@codeaurora.org>
Cc: Brian Starkey <brian.star...@arm.com>
Cc: Vincent Donnefort <vincent.donnef...@arm.com>
Cc: Sudipto Paul <sudipto.p...@arm.com>
Cc: Andrew F. Davis <a...@ti.com>
Cc: Xu YiPing <xuyip...@hisilicon.com>
Cc: "Chenfeng (puck)" <puck.c...@hisilicon.com>
Cc: butao <bu...@hisilicon.com>
Cc: "Xiaqing (A)" <saberlily....@hisilicon.com>
Cc: Yudongbin <yudong...@hisilicon.com>
Cc: Christoph Hellwig <h...@infradead.org>
Cc: Chenbo Feng <fe...@google.com>
Cc: Alistair Strachan <astrac...@google.com>
Cc: dri-devel@lists.freedesktop.org
Signed-off-by: Andrew F. Davis <a...@ti.com>
[Renamed and refactored dma_buf_phys driver, rewote commitlog]
Signed-off-by: John Stultz <john.stu...@linaro.org>
---
 drivers/dma-buf/Kconfig              |   6 +
 drivers/dma-buf/Makefile             |   1 +
 drivers/dma-buf/dma-buf-testdev.c    | 239 +++++++++++++++++++++++++++++++++++
 include/uapi/linux/dma-buf-testdev.h |  37 ++++++
 4 files changed, 283 insertions(+)
 create mode 100644 drivers/dma-buf/dma-buf-testdev.c
 create mode 100644 include/uapi/linux/dma-buf-testdev.h

diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig
index 63c139d..3cbcbe0 100644
--- a/drivers/dma-buf/Kconfig
+++ b/drivers/dma-buf/Kconfig
@@ -49,4 +49,10 @@ menuconfig DMABUF_HEAPS
 
 source "drivers/dma-buf/heaps/Kconfig"
 
+config DMABUF_TESTDEV
+       bool "DMA-BUF Dummy Test Device"
+       depends on DMA_SHARED_BUFFER
+       help
+         This provides a dummy test device that can be used to test
+         importing dma-bufs.
 endmenu
diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
index 09c2f2d..69bf45d 100644
--- a/drivers/dma-buf/Makefile
+++ b/drivers/dma-buf/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_DMABUF_HEAPS)      += dma-heap.o
 obj-$(CONFIG_SYNC_FILE)                += sync_file.o
 obj-$(CONFIG_SW_SYNC)          += sw_sync.o sync_debug.o
 obj-$(CONFIG_UDMABUF)          += udmabuf.o
+obj-$(CONFIG_DMABUF_TESTDEV)   += dma-buf-testdev.o
diff --git a/drivers/dma-buf/dma-buf-testdev.c 
b/drivers/dma-buf/dma-buf-testdev.c
new file mode 100644
index 0000000..dc3ed93
--- /dev/null
+++ b/drivers/dma-buf/dma-buf-testdev.c
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DMA-BUF Dummy Importer Test Device
+ *
+ * Originally from TI DMA BUF contiguous buffer physical address
+ * user-space exporter
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ *     Andrew F. Davis <a...@ti.com>
+ */
+
+#include <linux/device.h>
+#include <linux/dma-buf.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include <uapi/linux/dma-buf-testdev.h>
+
+#define DEVICE_NAME "dma-buf-testdev"
+
+struct dma_buf_testdev_priv {
+       struct miscdevice miscdev;
+};
+
+struct dma_buf_testdev_file {
+       struct device *dev;
+       struct dma_buf *dma_buf;
+       struct dma_buf_attachment *attachment;
+       struct sg_table *sgt;
+};
+
+static int dma_buf_testdev_open(struct inode *inode, struct file *file)
+{
+       struct miscdevice *miscdev = file->private_data;
+       struct device *dev = miscdev->this_device;
+       struct dma_buf_testdev_file *priv;
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+       priv->dev = dev;
+       file->private_data = (void *)priv;
+
+       return 0;
+}
+
+static int dma_buf_testdev_release(struct inode *inode, struct file *file)
+{
+       struct dma_buf_testdev_file *priv = file->private_data;
+
+       if (priv->attachment && priv->sgt)
+               dma_buf_unmap_attachment(priv->attachment, priv->sgt,
+                                        DMA_BIDIRECTIONAL);
+       if (priv->dma_buf && priv->attachment)
+               dma_buf_detach(priv->dma_buf, priv->attachment);
+       if (priv->dma_buf)
+               dma_buf_put(priv->dma_buf);
+
+       kfree(priv);
+
+       return 0;
+}
+
+static int dma_buf_testdev_convert(struct dma_buf_testdev_file *priv, int fd,
+                                  phys_addr_t *phys)
+{
+       struct device *dev = priv->dev;
+       struct dma_buf *dma_buf;
+       struct dma_buf_attachment *attachment;
+       struct sg_table *sgt;
+       dma_addr_t dma_addr;
+       int ret;
+
+       dma_buf = dma_buf_get(fd);
+       if (IS_ERR(dma_buf))
+               return PTR_ERR(dma_buf);
+
+       /* Attach as the parent device as it will have the correct DMA ops */
+       attachment = dma_buf_attach(dma_buf, dev->parent);
+       if (IS_ERR(attachment)) {
+               ret = PTR_ERR(attachment);
+               goto fail_put;
+       }
+
+       sgt = dma_buf_map_attachment(attachment, DMA_BIDIRECTIONAL);
+       if (IS_ERR(sgt)) {
+               ret = PTR_ERR(sgt);
+               goto fail_detach;
+       }
+
+       /* Without PAT only physically contiguous buffers can be supported */
+       if (sgt->orig_nents != 1) {
+               dev_err(dev, "DMA-BUF not contiguous\n");
+               ret = -EINVAL;
+               goto fail_unmap;
+       }
+
+       dma_addr = sg_dma_address(sgt->sgl);
+
+       *phys = dma_addr;
+
+       priv->dma_buf = dma_buf;
+       priv->attachment = attachment;
+       priv->sgt = sgt;
+
+       return 0;
+
+fail_unmap:
+       dma_buf_unmap_attachment(attachment, sgt, DMA_BIDIRECTIONAL);
+fail_detach:
+       dma_buf_detach(dma_buf, attachment);
+fail_put:
+       dma_buf_put(dma_buf);
+
+       return ret;
+}
+
+static long dma_buf_testdev_ioctl(struct file *file, unsigned int cmd,
+                                 unsigned long arg)
+{
+       struct dma_buf_testdev_file *priv = file->private_data;
+
+       switch (cmd) {
+       case DMA_BUF_TESTDEV_IOC_CONVERT:
+       {
+               struct dma_buf_testdev_data data;
+               int ret;
+
+               /*
+                * TODO: this should likely be properly serialized, but I
+                * see no reason this file would ever need to be shared.
+                */
+               /* one attachment per file */
+               if (priv->dma_buf)
+                       return -EFAULT;
+
+               if (copy_from_user(&data, (void __user *)arg, _IOC_SIZE(cmd)))
+                       return -EFAULT;
+
+               ret = dma_buf_testdev_convert(priv, data.fd, &data.phys);
+               if (ret)
+                       return ret;
+
+               if (copy_to_user((void __user *)arg, &data, _IOC_SIZE(cmd)))
+                       return -EFAULT;
+
+               break;
+       }
+       default:
+               return -ENOTTY;
+       }
+
+       return 0;
+}
+
+static const struct file_operations dma_buf_testdev_fops = {
+       .owner = THIS_MODULE,
+       .open = dma_buf_testdev_open,
+       .release = dma_buf_testdev_release,
+       .unlocked_ioctl = dma_buf_testdev_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = dma_buf_testdev_ioctl,
+#endif
+};
+
+static int dma_buf_testdev_probe(struct platform_device *pdev)
+{
+       struct dma_buf_testdev_priv *priv;
+       struct device *dev = &pdev->dev;
+       int err;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+       dev_set_drvdata(dev, priv);
+
+       dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
+
+       if (!dev->dma_parms) {
+               dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms),
+                                             GFP_KERNEL);
+               if (!dev->dma_parms)
+                       return -ENOMEM;
+       }
+       dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
+
+       priv->miscdev.minor = MISC_DYNAMIC_MINOR;
+       priv->miscdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s",
+                                           DEVICE_NAME);
+       priv->miscdev.fops = &dma_buf_testdev_fops;
+       priv->miscdev.parent = dev;
+       err = misc_register(&priv->miscdev);
+       if (err) {
+               dev_err(dev,
+                       "unable to register DMA-BUF to Phys misc device\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static int dma_buf_testdev_remove(struct platform_device *pdev)
+{
+       struct dma_buf_testdev_priv *priv = dev_get_drvdata(&pdev->dev);
+
+       misc_deregister(&priv->miscdev);
+
+       return 0;
+}
+
+static struct platform_driver dma_buf_testdev_driver = {
+       .probe = dma_buf_testdev_probe,
+       .remove = dma_buf_testdev_remove,
+       .driver = {
+               .name = "dma_buf_testdev",
+       }
+};
+module_platform_driver(dma_buf_testdev_driver);
+
+static int __init dma_buf_testdev_init(void)
+{
+       struct platform_device *pdev;
+
+       pdev = platform_device_register_simple("dma_buf_testdev", -1, NULL, 0);
+
+       return PTR_ERR_OR_ZERO(pdev);
+}
+
+postcore_initcall(dma_buf_testdev_init);
+
+MODULE_AUTHOR("Andrew F. Davis <a...@ti.com>");
+MODULE_DESCRIPTION("DMA-BUF Dummy Importer Test Device");
+MODULE_LICENSE("GPL v2");
diff --git a/include/uapi/linux/dma-buf-testdev.h 
b/include/uapi/linux/dma-buf-testdev.h
new file mode 100644
index 0000000..b9706b8
--- /dev/null
+++ b/include/uapi/linux/dma-buf-testdev.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * DMA-BUF Dummy Importer Test Device
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ *     Andrew F. Davis <a...@ti.com>
+ */
+
+#ifndef DMA_BUF_TESTDEV_H
+#define DMA_BUF_TESTDEV_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+/**
+ * struct dma_buf_testdev_data - metadata passed from userspace for conversion
+ * @fd:                DMA-BUF fd for conversion
+ * @phys:      populated with CPU physical address of DMA-BUF
+ */
+struct dma_buf_testdev_data {
+       __u32 fd;
+       __u64 phys;
+};
+
+#define DMA_BUF_TESTDEV_IOC_MAGIC 'D'
+
+/**
+ * DOC: DMA_BUF_TESTDEV_IOC_CONVERT - Convert DMA-BUF to physical address
+ *
+ * Takes a dma_buf_testdev_data struct containing a fd for a
+ * physicaly contigous buffer. Pins this buffer and populates
+ * phys field with the CPU physical address.
+ */
+#define DMA_BUF_TESTDEV_IOC_CONVERT _IOWR(DMA_BUF_TESTDEV_IOC_MAGIC, 0, \
+                                         struct dma_buf_testdev_data)
+
+#endif /* DMA_BUF_PHYS_H */
-- 
2.7.4

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to