Merge tag 'drm-intel-next-2019-12-23' of git://anongit.freedesktop.org/drm/drm-intel...
[platform/kernel/linux-rpi.git] / drivers / dma-buf / dma-heap.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Framework for userspace DMA-BUF allocations
4  *
5  * Copyright (C) 2011 Google, Inc.
6  * Copyright (C) 2019 Linaro Ltd.
7  */
8
9 #include <linux/cdev.h>
10 #include <linux/debugfs.h>
11 #include <linux/device.h>
12 #include <linux/dma-buf.h>
13 #include <linux/err.h>
14 #include <linux/xarray.h>
15 #include <linux/list.h>
16 #include <linux/slab.h>
17 #include <linux/uaccess.h>
18 #include <linux/syscalls.h>
19 #include <linux/dma-heap.h>
20 #include <uapi/linux/dma-heap.h>
21
22 #define DEVNAME "dma_heap"
23
24 #define NUM_HEAP_MINORS 128
25
26 /**
27  * struct dma_heap - represents a dmabuf heap in the system
28  * @name:               used for debugging/device-node name
29  * @ops:                ops struct for this heap
30  * @heap_devt           heap device node
31  * @list                list head connecting to list of heaps
32  * @heap_cdev           heap char device
33  *
34  * Represents a heap of memory from which buffers can be made.
35  */
36 struct dma_heap {
37         const char *name;
38         const struct dma_heap_ops *ops;
39         void *priv;
40         dev_t heap_devt;
41         struct list_head list;
42         struct cdev heap_cdev;
43 };
44
45 static LIST_HEAD(heap_list);
46 static DEFINE_MUTEX(heap_list_lock);
47 static dev_t dma_heap_devt;
48 static struct class *dma_heap_class;
49 static DEFINE_XARRAY_ALLOC(dma_heap_minors);
50
51 static int dma_heap_buffer_alloc(struct dma_heap *heap, size_t len,
52                                  unsigned int fd_flags,
53                                  unsigned int heap_flags)
54 {
55         /*
56          * Allocations from all heaps have to begin
57          * and end on page boundaries.
58          */
59         len = PAGE_ALIGN(len);
60         if (!len)
61                 return -EINVAL;
62
63         return heap->ops->allocate(heap, len, fd_flags, heap_flags);
64 }
65
66 static int dma_heap_open(struct inode *inode, struct file *file)
67 {
68         struct dma_heap *heap;
69
70         heap = xa_load(&dma_heap_minors, iminor(inode));
71         if (!heap) {
72                 pr_err("dma_heap: minor %d unknown.\n", iminor(inode));
73                 return -ENODEV;
74         }
75
76         /* instance data as context */
77         file->private_data = heap;
78         nonseekable_open(inode, file);
79
80         return 0;
81 }
82
83 static long dma_heap_ioctl_allocate(struct file *file, void *data)
84 {
85         struct dma_heap_allocation_data *heap_allocation = data;
86         struct dma_heap *heap = file->private_data;
87         int fd;
88
89         if (heap_allocation->fd)
90                 return -EINVAL;
91
92         if (heap_allocation->fd_flags & ~DMA_HEAP_VALID_FD_FLAGS)
93                 return -EINVAL;
94
95         if (heap_allocation->heap_flags & ~DMA_HEAP_VALID_HEAP_FLAGS)
96                 return -EINVAL;
97
98         fd = dma_heap_buffer_alloc(heap, heap_allocation->len,
99                                    heap_allocation->fd_flags,
100                                    heap_allocation->heap_flags);
101         if (fd < 0)
102                 return fd;
103
104         heap_allocation->fd = fd;
105
106         return 0;
107 }
108
109 unsigned int dma_heap_ioctl_cmds[] = {
110         DMA_HEAP_IOC_ALLOC,
111 };
112
113 static long dma_heap_ioctl(struct file *file, unsigned int ucmd,
114                            unsigned long arg)
115 {
116         char stack_kdata[128];
117         char *kdata = stack_kdata;
118         unsigned int kcmd;
119         unsigned int in_size, out_size, drv_size, ksize;
120         int nr = _IOC_NR(ucmd);
121         int ret = 0;
122
123         if (nr >= ARRAY_SIZE(dma_heap_ioctl_cmds))
124                 return -EINVAL;
125
126         /* Get the kernel ioctl cmd that matches */
127         kcmd = dma_heap_ioctl_cmds[nr];
128
129         /* Figure out the delta between user cmd size and kernel cmd size */
130         drv_size = _IOC_SIZE(kcmd);
131         out_size = _IOC_SIZE(ucmd);
132         in_size = out_size;
133         if ((ucmd & kcmd & IOC_IN) == 0)
134                 in_size = 0;
135         if ((ucmd & kcmd & IOC_OUT) == 0)
136                 out_size = 0;
137         ksize = max(max(in_size, out_size), drv_size);
138
139         /* If necessary, allocate buffer for ioctl argument */
140         if (ksize > sizeof(stack_kdata)) {
141                 kdata = kmalloc(ksize, GFP_KERNEL);
142                 if (!kdata)
143                         return -ENOMEM;
144         }
145
146         if (copy_from_user(kdata, (void __user *)arg, in_size) != 0) {
147                 ret = -EFAULT;
148                 goto err;
149         }
150
151         /* zero out any difference between the kernel/user structure size */
152         if (ksize > in_size)
153                 memset(kdata + in_size, 0, ksize - in_size);
154
155         switch (kcmd) {
156         case DMA_HEAP_IOC_ALLOC:
157                 ret = dma_heap_ioctl_allocate(file, kdata);
158                 break;
159         default:
160                 return -ENOTTY;
161         }
162
163         if (copy_to_user((void __user *)arg, kdata, out_size) != 0)
164                 ret = -EFAULT;
165 err:
166         if (kdata != stack_kdata)
167                 kfree(kdata);
168         return ret;
169 }
170
171 static const struct file_operations dma_heap_fops = {
172         .owner          = THIS_MODULE,
173         .open           = dma_heap_open,
174         .unlocked_ioctl = dma_heap_ioctl,
175 #ifdef CONFIG_COMPAT
176         .compat_ioctl   = dma_heap_ioctl,
177 #endif
178 };
179
180 /**
181  * dma_heap_get_drvdata() - get per-subdriver data for the heap
182  * @heap: DMA-Heap to retrieve private data for
183  *
184  * Returns:
185  * The per-subdriver data for the heap.
186  */
187 void *dma_heap_get_drvdata(struct dma_heap *heap)
188 {
189         return heap->priv;
190 }
191
192 struct dma_heap *dma_heap_add(const struct dma_heap_export_info *exp_info)
193 {
194         struct dma_heap *heap, *h, *err_ret;
195         struct device *dev_ret;
196         unsigned int minor;
197         int ret;
198
199         if (!exp_info->name || !strcmp(exp_info->name, "")) {
200                 pr_err("dma_heap: Cannot add heap without a name\n");
201                 return ERR_PTR(-EINVAL);
202         }
203
204         if (!exp_info->ops || !exp_info->ops->allocate) {
205                 pr_err("dma_heap: Cannot add heap with invalid ops struct\n");
206                 return ERR_PTR(-EINVAL);
207         }
208
209         /* check the name is unique */
210         mutex_lock(&heap_list_lock);
211         list_for_each_entry(h, &heap_list, list) {
212                 if (!strcmp(h->name, exp_info->name)) {
213                         mutex_unlock(&heap_list_lock);
214                         pr_err("dma_heap: Already registered heap named %s\n",
215                                exp_info->name);
216                         return ERR_PTR(-EINVAL);
217                 }
218         }
219         mutex_unlock(&heap_list_lock);
220
221         heap = kzalloc(sizeof(*heap), GFP_KERNEL);
222         if (!heap)
223                 return ERR_PTR(-ENOMEM);
224
225         heap->name = exp_info->name;
226         heap->ops = exp_info->ops;
227         heap->priv = exp_info->priv;
228
229         /* Find unused minor number */
230         ret = xa_alloc(&dma_heap_minors, &minor, heap,
231                        XA_LIMIT(0, NUM_HEAP_MINORS - 1), GFP_KERNEL);
232         if (ret < 0) {
233                 pr_err("dma_heap: Unable to get minor number for heap\n");
234                 err_ret = ERR_PTR(ret);
235                 goto err0;
236         }
237
238         /* Create device */
239         heap->heap_devt = MKDEV(MAJOR(dma_heap_devt), minor);
240
241         cdev_init(&heap->heap_cdev, &dma_heap_fops);
242         ret = cdev_add(&heap->heap_cdev, heap->heap_devt, 1);
243         if (ret < 0) {
244                 pr_err("dma_heap: Unable to add char device\n");
245                 err_ret = ERR_PTR(ret);
246                 goto err1;
247         }
248
249         dev_ret = device_create(dma_heap_class,
250                                 NULL,
251                                 heap->heap_devt,
252                                 NULL,
253                                 heap->name);
254         if (IS_ERR(dev_ret)) {
255                 pr_err("dma_heap: Unable to create device\n");
256                 err_ret = ERR_CAST(dev_ret);
257                 goto err2;
258         }
259         /* Add heap to the list */
260         mutex_lock(&heap_list_lock);
261         list_add(&heap->list, &heap_list);
262         mutex_unlock(&heap_list_lock);
263
264         return heap;
265
266 err2:
267         cdev_del(&heap->heap_cdev);
268 err1:
269         xa_erase(&dma_heap_minors, minor);
270 err0:
271         kfree(heap);
272         return err_ret;
273 }
274
275 static char *dma_heap_devnode(struct device *dev, umode_t *mode)
276 {
277         return kasprintf(GFP_KERNEL, "dma_heap/%s", dev_name(dev));
278 }
279
280 static int dma_heap_init(void)
281 {
282         int ret;
283
284         ret = alloc_chrdev_region(&dma_heap_devt, 0, NUM_HEAP_MINORS, DEVNAME);
285         if (ret)
286                 return ret;
287
288         dma_heap_class = class_create(THIS_MODULE, DEVNAME);
289         if (IS_ERR(dma_heap_class)) {
290                 unregister_chrdev_region(dma_heap_devt, NUM_HEAP_MINORS);
291                 return PTR_ERR(dma_heap_class);
292         }
293         dma_heap_class->devnode = dma_heap_devnode;
294
295         return 0;
296 }
297 subsys_initcall(dma_heap_init);