aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew F. Davis2019-09-05 08:09:16 -0500
committerTero Kristo2019-09-06 15:30:43 -0500
commit6cc31c44e7a3f17416e56298e3393b96e2d69b11 (patch)
tree53b799f6ca3329de9604d90d473324b4d9ed696d
parent55eaa0cee89a4f16fdc47e2db4de9279e00568e0 (diff)
downloadkernel-6cc31c44e7a3f17416e56298e3393b96e2d69b11.tar.gz
kernel-6cc31c44e7a3f17416e56298e3393b96e2d69b11.tar.xz
kernel-6cc31c44e7a3f17416e56298e3393b96e2d69b11.zip
HACK: misc: Add dma-buf to physical address exporter
This is driver allows user-space to attach a DMA-BUF and receive back its CPU physical address. This is a temporary solution to allow CMEM like functionality from ION allocated buffers. This is a hack and this will be removed when proper solutions are implemented. Signed-off-by: Andrew F. Davis <afd@ti.com>
-rw-r--r--drivers/misc/Kconfig5
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/dma-buf-phys.c217
-rw-r--r--include/uapi/linux/dma_buf_phys.h35
4 files changed, 258 insertions, 0 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 3726eacdf65d..6d3635552160 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -513,6 +513,11 @@ config MISC_RTSX
513 tristate 513 tristate
514 default MISC_RTSX_PCI || MISC_RTSX_USB 514 default MISC_RTSX_PCI || MISC_RTSX_USB
515 515
516config DMA_BUF_PHYS
517 tristate "DMA-BUF physical address user-space exporter"
518 help
519 Exports CPU physical address of DMA-BUF to user-space.
520
516source "drivers/misc/c2port/Kconfig" 521source "drivers/misc/c2port/Kconfig"
517source "drivers/misc/eeprom/Kconfig" 522source "drivers/misc/eeprom/Kconfig"
518source "drivers/misc/cb710/Kconfig" 523source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index af22bbc3d00c..efe8447c115b 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -58,3 +58,4 @@ obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
58obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o 58obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o
59obj-$(CONFIG_OCXL) += ocxl/ 59obj-$(CONFIG_OCXL) += ocxl/
60obj-$(CONFIG_MISC_RTSX) += cardreader/ 60obj-$(CONFIG_MISC_RTSX) += cardreader/
61obj-$(CONFIG_DMA_BUF_PHYS) += dma-buf-phys.o
diff --git a/drivers/misc/dma-buf-phys.c b/drivers/misc/dma-buf-phys.c
new file mode 100644
index 000000000000..277546f4688b
--- /dev/null
+++ b/drivers/misc/dma-buf-phys.c
@@ -0,0 +1,217 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * DMA-BUF contiguous buffer physical address user-space exporter
4 *
5 * Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/
6 * Andrew F. Davis <afd@ti.com>
7 */
8
9#include <linux/device.h>
10#include <linux/dma-buf.h>
11#include <linux/err.h>
12#include <linux/kernel.h>
13#include <linux/miscdevice.h>
14#include <linux/module.h>
15#include <linux/of_device.h>
16#include <linux/platform_device.h>
17#include <linux/slab.h>
18#include <linux/uaccess.h>
19
20#include <uapi/linux/dma_buf_phys.h>
21
22#define DEVICE_NAME "dma-buf-phys"
23
24struct dma_buf_phys_priv {
25 struct miscdevice miscdev;
26};
27
28struct dma_buf_phys_file {
29 struct device *dev;
30 struct dma_buf *dma_buf;
31 struct dma_buf_attachment *attachment;
32 struct sg_table *sgt;
33};
34
35static int dma_buf_phys_open(struct inode *inode, struct file *file)
36{
37 struct miscdevice *miscdev = file->private_data;
38 struct device *dev = miscdev->this_device;
39 struct dma_buf_phys_file *priv;
40
41 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
42 if (!priv)
43 return -ENOMEM;
44 priv->dev = dev;
45 file->private_data = (void *)priv;
46
47 return 0;
48}
49
50static int dma_buf_phys_release(struct inode *inode, struct file *file)
51{
52 struct dma_buf_phys_file *priv = file->private_data;
53
54 if (priv->attachment && priv->sgt)
55 dma_buf_unmap_attachment(priv->attachment, priv->sgt, DMA_BIDIRECTIONAL);
56 if (priv->dma_buf && priv->attachment)
57 dma_buf_detach(priv->dma_buf, priv->attachment);
58 if (priv->dma_buf)
59 dma_buf_put(priv->dma_buf);
60
61 kfree(priv);
62
63 return 0;
64}
65
66static int dma_buf_phys_convert(struct dma_buf_phys_file *priv, int fd, u64 *phys)
67{
68 struct device *dev = priv->dev;
69 struct dma_buf *dma_buf;
70 struct dma_buf_attachment *attachment;
71 struct sg_table *sgt;
72 dma_addr_t dma_addr;
73 int ret;
74
75 dma_buf = dma_buf_get(fd);
76 if (IS_ERR(dma_buf))
77 return PTR_ERR(dma_buf);
78
79 /* Attach as the parent device as it will have the correct DMA ops set */
80 attachment = dma_buf_attach(dma_buf, dev->parent);
81 if (IS_ERR(attachment)) {
82 ret = PTR_ERR(attachment);
83 goto fail_put;
84 }
85
86 sgt = dma_buf_map_attachment(attachment, DMA_BIDIRECTIONAL);
87 if (IS_ERR(sgt)) {
88 ret = PTR_ERR(sgt);
89 goto fail_detach;
90 }
91
92 /* Without PAT only physically contiguous buffers can be supported */
93 if (sgt->orig_nents != 1) {
94 dev_err(dev, "DMA-BUF not contiguous\n");
95 ret = -EINVAL;
96 goto fail_unmap;
97 }
98
99 dma_addr = sg_dma_address(sgt->sgl);
100
101 *phys = dma_addr;
102
103 priv->dma_buf = dma_buf;
104 priv->attachment = attachment;
105 priv->sgt = sgt;
106
107 return 0;
108
109fail_unmap:
110 dma_buf_unmap_attachment(attachment, sgt, DMA_BIDIRECTIONAL);
111fail_detach:
112 dma_buf_detach(dma_buf, attachment);
113fail_put:
114 dma_buf_put(dma_buf);
115
116 return ret;
117}
118
119static long dma_buf_phys_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
120{
121 struct dma_buf_phys_file *priv = file->private_data;
122
123 switch (cmd) {
124 case DMA_BUF_PHYS_IOC_CONVERT:
125 {
126 struct dma_buf_phys_data data;
127 int ret;
128
129 /*
130 * TODO: this should likely be properly serialized, but I
131 * see no reason this file would ever need to be shared.
132 */
133 /* one attachment per file */
134 if (priv->dma_buf)
135 return -EFAULT;
136
137 if (copy_from_user(&data, (void __user *)arg, _IOC_SIZE(cmd)))
138 return -EFAULT;
139
140 ret = dma_buf_phys_convert(priv, data.fd, &data.phys);
141 if (ret)
142 return ret;
143
144 if (copy_to_user((void __user *)arg, &data, _IOC_SIZE(cmd)))
145 return -EFAULT;
146
147 break;
148 }
149 default:
150 return -ENOTTY;
151 }
152
153 return 0;
154}
155
156static const struct file_operations dma_buf_phys_fops = {
157 .owner = THIS_MODULE,
158 .open = dma_buf_phys_open,
159 .release = dma_buf_phys_release,
160 .unlocked_ioctl = dma_buf_phys_ioctl,
161#ifdef CONFIG_COMPAT
162 .compat_ioctl = dma_buf_phys_ioctl,
163#endif
164};
165
166static int dma_buf_phys_probe(struct platform_device *pdev)
167{
168 struct dma_buf_phys_priv *priv;
169 struct device *dev = &pdev->dev;
170 int err;
171
172 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
173 if (!priv)
174 return -ENOMEM;
175 dev_set_drvdata(dev, priv);
176
177 priv->miscdev.minor = MISC_DYNAMIC_MINOR;
178 priv->miscdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s", DEVICE_NAME);
179 priv->miscdev.fops = &dma_buf_phys_fops;
180 priv->miscdev.parent = dev;
181 err = misc_register(&priv->miscdev);
182 if (err) {
183 dev_err(dev, "unable to register DMA-BUF to Phys misc device\n");
184 return err;
185 }
186
187 return 0;
188}
189
190static int dma_buf_phys_remove(struct platform_device *pdev)
191{
192 struct dma_buf_phys_priv *priv = dev_get_drvdata(&pdev->dev);
193
194 misc_deregister(&priv->miscdev);
195
196 return 0;
197}
198
199static const struct of_device_id dma_buf_phys_of_match[] = {
200 { .compatible = "ti,dma_buf_phys", },
201 {},
202};
203MODULE_DEVICE_TABLE(of, dma_buf_phys_of_match);
204
205static struct platform_driver dma_buf_phys_driver = {
206 .probe = dma_buf_phys_probe,
207 .remove = dma_buf_phys_remove,
208 .driver = {
209 .name = "dma_buf_phys",
210 .of_match_table = dma_buf_phys_of_match,
211 }
212};
213module_platform_driver(dma_buf_phys_driver);
214
215MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
216MODULE_DESCRIPTION("DMA-BUF contiguous buffer physical address user-space exporter");
217MODULE_LICENSE("GPL v2");
diff --git a/include/uapi/linux/dma_buf_phys.h b/include/uapi/linux/dma_buf_phys.h
new file mode 100644
index 000000000000..72d9d9e4b225
--- /dev/null
+++ b/include/uapi/linux/dma_buf_phys.h
@@ -0,0 +1,35 @@
1/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
2/*
3 * DMA-BUF contiguous buffer physical address user-space exporter
4 *
5 * Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/
6 * Andrew F. Davis <afd@ti.com>
7 */
8
9#ifndef DMA_BUF_PHYS_H
10#define DMA_BUF_PHYS_H
11
12#include <linux/ioctl.h>
13#include <linux/types.h>
14
15/**
16 * struct dma_buf_phys_data - metadata passed from userspace for conversion
17 * @fd: DMA-BUF fd for conversion
18 * @phys: populated with CPU physical address of DMA-BUF
19 */
20struct dma_buf_phys_data {
21 __u32 fd;
22 __u64 phys;
23};
24
25#define DMA_BUF_PHYS_IOC_MAGIC 'D'
26
27/**
28 * DOC: DMA_BUF_PHYS_IOC_CONVERT - Convert DMA-BUF to physical address
29 *
30 * Takes a dma_buf_phys_data struct containing a fd for a physicaly contigous
31 * buffer. Pins this buffer and populates phys field with the CPU physical address.
32 */
33#define DMA_BUF_PHYS_IOC_CONVERT _IOWR(DMA_BUF_PHYS_IOC_MAGIC, 0, struct dma_buf_phys_data)
34
35#endif /* DMA_BUF_PHYS_H */