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