xref: /openbmc/linux/drivers/gpu/drm/vgem/vgem_drv.c (revision a6ca5ac746d104019e76c29e69c2a1fc6dd2b29f)
1 /*
2  * Copyright 2011 Red Hat, Inc.
3  * Copyright © 2014 The Chromium OS Authors
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software")
7  * to deal in the software without restriction, including without limitation
8  * on the rights to use, copy, modify, merge, publish, distribute, sub
9  * license, and/or sell copies of the Software, and to permit persons to whom
10  * them Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTIBILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER
20  * IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  *
23  * Authors:
24  *	Adam Jackson <ajax@redhat.com>
25  *	Ben Widawsky <ben@bwidawsk.net>
26  */
27 
28 /**
29  * This is vgem, a (non-hardware-backed) GEM service.  This is used by Mesa's
30  * software renderer and the X server for efficient buffer sharing.
31  */
32 
33 #include <linux/module.h>
34 #include <linux/ramfs.h>
35 #include <linux/shmem_fs.h>
36 #include <linux/dma-buf.h>
37 #include "vgem_drv.h"
38 
39 #define DRIVER_NAME	"vgem"
40 #define DRIVER_DESC	"Virtual GEM provider"
41 #define DRIVER_DATE	"20120112"
42 #define DRIVER_MAJOR	1
43 #define DRIVER_MINOR	0
44 
45 static struct vgem_device {
46 	struct drm_device drm;
47 	struct platform_device *platform;
48 } *vgem_device;
49 
50 static void vgem_gem_free_object(struct drm_gem_object *obj)
51 {
52 	struct drm_vgem_gem_object *vgem_obj = to_vgem_bo(obj);
53 
54 	drm_free_large(vgem_obj->pages);
55 
56 	if (obj->import_attach)
57 		drm_prime_gem_destroy(obj, vgem_obj->table);
58 
59 	drm_gem_object_release(obj);
60 	kfree(vgem_obj);
61 }
62 
63 static int vgem_gem_fault(struct vm_fault *vmf)
64 {
65 	struct vm_area_struct *vma = vmf->vma;
66 	struct drm_vgem_gem_object *obj = vma->vm_private_data;
67 	/* We don't use vmf->pgoff since that has the fake offset */
68 	unsigned long vaddr = vmf->address;
69 	int ret;
70 	loff_t num_pages;
71 	pgoff_t page_offset;
72 	page_offset = (vaddr - vma->vm_start) >> PAGE_SHIFT;
73 
74 	num_pages = DIV_ROUND_UP(obj->base.size, PAGE_SIZE);
75 
76 	if (page_offset > num_pages)
77 		return VM_FAULT_SIGBUS;
78 
79 	if (obj->pages) {
80 		get_page(obj->pages[page_offset]);
81 		vmf->page = obj->pages[page_offset];
82 		ret = 0;
83 	} else {
84 		struct page *page;
85 
86 		page = shmem_read_mapping_page(
87 					file_inode(obj->base.filp)->i_mapping,
88 					page_offset);
89 		if (!IS_ERR(page)) {
90 			vmf->page = page;
91 			ret = 0;
92 		} else switch (PTR_ERR(page)) {
93 			case -ENOSPC:
94 			case -ENOMEM:
95 				ret = VM_FAULT_OOM;
96 				break;
97 			case -EBUSY:
98 				ret = VM_FAULT_RETRY;
99 				break;
100 			case -EFAULT:
101 			case -EINVAL:
102 				ret = VM_FAULT_SIGBUS;
103 				break;
104 			default:
105 				WARN_ON(PTR_ERR(page));
106 				ret = VM_FAULT_SIGBUS;
107 				break;
108 		}
109 
110 	}
111 	return ret;
112 }
113 
114 static const struct vm_operations_struct vgem_gem_vm_ops = {
115 	.fault = vgem_gem_fault,
116 	.open = drm_gem_vm_open,
117 	.close = drm_gem_vm_close,
118 };
119 
120 static int vgem_open(struct drm_device *dev, struct drm_file *file)
121 {
122 	struct vgem_file *vfile;
123 	int ret;
124 
125 	vfile = kzalloc(sizeof(*vfile), GFP_KERNEL);
126 	if (!vfile)
127 		return -ENOMEM;
128 
129 	file->driver_priv = vfile;
130 
131 	ret = vgem_fence_open(vfile);
132 	if (ret) {
133 		kfree(vfile);
134 		return ret;
135 	}
136 
137 	return 0;
138 }
139 
140 static void vgem_postclose(struct drm_device *dev, struct drm_file *file)
141 {
142 	struct vgem_file *vfile = file->driver_priv;
143 
144 	vgem_fence_close(vfile);
145 	kfree(vfile);
146 }
147 
148 static struct drm_vgem_gem_object *__vgem_gem_create(struct drm_device *dev,
149 						unsigned long size)
150 {
151 	struct drm_vgem_gem_object *obj;
152 	int ret;
153 
154 	obj = kzalloc(sizeof(*obj), GFP_KERNEL);
155 	if (!obj)
156 		return ERR_PTR(-ENOMEM);
157 
158 	ret = drm_gem_object_init(dev, &obj->base, roundup(size, PAGE_SIZE));
159 	if (ret) {
160 		kfree(obj);
161 		return ERR_PTR(ret);
162 	}
163 
164 	return obj;
165 }
166 
167 static void __vgem_gem_destroy(struct drm_vgem_gem_object *obj)
168 {
169 	drm_gem_object_release(&obj->base);
170 	kfree(obj);
171 }
172 
173 static struct drm_gem_object *vgem_gem_create(struct drm_device *dev,
174 					      struct drm_file *file,
175 					      unsigned int *handle,
176 					      unsigned long size)
177 {
178 	struct drm_vgem_gem_object *obj;
179 	int ret;
180 
181 	obj = __vgem_gem_create(dev, size);
182 	if (IS_ERR(obj))
183 		return ERR_CAST(obj);
184 
185 	ret = drm_gem_handle_create(file, &obj->base, handle);
186 	drm_gem_object_unreference_unlocked(&obj->base);
187 	if (ret)
188 		goto err;
189 
190 	return &obj->base;
191 
192 err:
193 	__vgem_gem_destroy(obj);
194 	return ERR_PTR(ret);
195 }
196 
197 static int vgem_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
198 				struct drm_mode_create_dumb *args)
199 {
200 	struct drm_gem_object *gem_object;
201 	u64 pitch, size;
202 
203 	pitch = args->width * DIV_ROUND_UP(args->bpp, 8);
204 	size = args->height * pitch;
205 	if (size == 0)
206 		return -EINVAL;
207 
208 	gem_object = vgem_gem_create(dev, file, &args->handle, size);
209 	if (IS_ERR(gem_object))
210 		return PTR_ERR(gem_object);
211 
212 	args->size = gem_object->size;
213 	args->pitch = pitch;
214 
215 	DRM_DEBUG_DRIVER("Created object of size %lld\n", size);
216 
217 	return 0;
218 }
219 
220 static int vgem_gem_dumb_map(struct drm_file *file, struct drm_device *dev,
221 			     uint32_t handle, uint64_t *offset)
222 {
223 	struct drm_gem_object *obj;
224 	int ret;
225 
226 	obj = drm_gem_object_lookup(file, handle);
227 	if (!obj)
228 		return -ENOENT;
229 
230 	if (!obj->filp) {
231 		ret = -EINVAL;
232 		goto unref;
233 	}
234 
235 	ret = drm_gem_create_mmap_offset(obj);
236 	if (ret)
237 		goto unref;
238 
239 	*offset = drm_vma_node_offset_addr(&obj->vma_node);
240 unref:
241 	drm_gem_object_unreference_unlocked(obj);
242 
243 	return ret;
244 }
245 
246 static struct drm_ioctl_desc vgem_ioctls[] = {
247 	DRM_IOCTL_DEF_DRV(VGEM_FENCE_ATTACH, vgem_fence_attach_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
248 	DRM_IOCTL_DEF_DRV(VGEM_FENCE_SIGNAL, vgem_fence_signal_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
249 };
250 
251 static int vgem_mmap(struct file *filp, struct vm_area_struct *vma)
252 {
253 	unsigned long flags = vma->vm_flags;
254 	int ret;
255 
256 	ret = drm_gem_mmap(filp, vma);
257 	if (ret)
258 		return ret;
259 
260 	/* Keep the WC mmaping set by drm_gem_mmap() but our pages
261 	 * are ordinary and not special.
262 	 */
263 	vma->vm_flags = flags | VM_DONTEXPAND | VM_DONTDUMP;
264 	return 0;
265 }
266 
267 static const struct file_operations vgem_driver_fops = {
268 	.owner		= THIS_MODULE,
269 	.open		= drm_open,
270 	.mmap		= vgem_mmap,
271 	.poll		= drm_poll,
272 	.read		= drm_read,
273 	.unlocked_ioctl = drm_ioctl,
274 	.release	= drm_release,
275 };
276 
277 static int vgem_prime_pin(struct drm_gem_object *obj)
278 {
279 	long n_pages = obj->size >> PAGE_SHIFT;
280 	struct page **pages;
281 
282 	/* Flush the object from the CPU cache so that importers can rely
283 	 * on coherent indirect access via the exported dma-address.
284 	 */
285 	pages = drm_gem_get_pages(obj);
286 	if (IS_ERR(pages))
287 		return PTR_ERR(pages);
288 
289 	drm_clflush_pages(pages, n_pages);
290 	drm_gem_put_pages(obj, pages, true, false);
291 
292 	return 0;
293 }
294 
295 static struct sg_table *vgem_prime_get_sg_table(struct drm_gem_object *obj)
296 {
297 	struct sg_table *st;
298 	struct page **pages;
299 
300 	pages = drm_gem_get_pages(obj);
301 	if (IS_ERR(pages))
302 		return ERR_CAST(pages);
303 
304 	st = drm_prime_pages_to_sg(pages, obj->size >> PAGE_SHIFT);
305 	drm_gem_put_pages(obj, pages, false, false);
306 
307 	return st;
308 }
309 
310 static struct drm_gem_object* vgem_prime_import(struct drm_device *dev,
311 						struct dma_buf *dma_buf)
312 {
313 	struct vgem_device *vgem = container_of(dev, typeof(*vgem), drm);
314 
315 	return drm_gem_prime_import_dev(dev, dma_buf, &vgem->platform->dev);
316 }
317 
318 static struct drm_gem_object *vgem_prime_import_sg_table(struct drm_device *dev,
319 			struct dma_buf_attachment *attach, struct sg_table *sg)
320 {
321 	struct drm_vgem_gem_object *obj;
322 	int npages;
323 
324 	obj = __vgem_gem_create(dev, attach->dmabuf->size);
325 	if (IS_ERR(obj))
326 		return ERR_CAST(obj);
327 
328 	npages = PAGE_ALIGN(attach->dmabuf->size) / PAGE_SIZE;
329 
330 	obj->table = sg;
331 	obj->pages = drm_malloc_ab(npages, sizeof(struct page *));
332 	if (!obj->pages) {
333 		__vgem_gem_destroy(obj);
334 		return ERR_PTR(-ENOMEM);
335 	}
336 	drm_prime_sg_to_page_addr_arrays(obj->table, obj->pages, NULL,
337 					npages);
338 	return &obj->base;
339 }
340 
341 static void *vgem_prime_vmap(struct drm_gem_object *obj)
342 {
343 	long n_pages = obj->size >> PAGE_SHIFT;
344 	struct page **pages;
345 	void *addr;
346 
347 	pages = drm_gem_get_pages(obj);
348 	if (IS_ERR(pages))
349 		return NULL;
350 
351 	addr = vmap(pages, n_pages, 0, pgprot_writecombine(PAGE_KERNEL));
352 	drm_gem_put_pages(obj, pages, false, false);
353 
354 	return addr;
355 }
356 
357 static void vgem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
358 {
359 	vunmap(vaddr);
360 }
361 
362 static int vgem_prime_mmap(struct drm_gem_object *obj,
363 			   struct vm_area_struct *vma)
364 {
365 	int ret;
366 
367 	if (obj->size < vma->vm_end - vma->vm_start)
368 		return -EINVAL;
369 
370 	if (!obj->filp)
371 		return -ENODEV;
372 
373 	ret = call_mmap(obj->filp, vma);
374 	if (ret)
375 		return ret;
376 
377 	fput(vma->vm_file);
378 	vma->vm_file = get_file(obj->filp);
379 	vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
380 	vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
381 
382 	return 0;
383 }
384 
385 static void vgem_release(struct drm_device *dev)
386 {
387 	struct vgem_device *vgem = container_of(dev, typeof(*vgem), drm);
388 
389 	platform_device_unregister(vgem->platform);
390 	drm_dev_fini(&vgem->drm);
391 
392 	kfree(vgem);
393 }
394 
395 static struct drm_driver vgem_driver = {
396 	.driver_features		= DRIVER_GEM | DRIVER_PRIME,
397 	.release			= vgem_release,
398 	.open				= vgem_open,
399 	.postclose			= vgem_postclose,
400 	.gem_free_object_unlocked	= vgem_gem_free_object,
401 	.gem_vm_ops			= &vgem_gem_vm_ops,
402 	.ioctls				= vgem_ioctls,
403 	.num_ioctls 			= ARRAY_SIZE(vgem_ioctls),
404 	.fops				= &vgem_driver_fops,
405 
406 	.dumb_create			= vgem_gem_dumb_create,
407 	.dumb_map_offset		= vgem_gem_dumb_map,
408 
409 	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
410 	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
411 	.gem_prime_pin = vgem_prime_pin,
412 	.gem_prime_import = vgem_prime_import,
413 	.gem_prime_export = drm_gem_prime_export,
414 	.gem_prime_import_sg_table = vgem_prime_import_sg_table,
415 	.gem_prime_get_sg_table = vgem_prime_get_sg_table,
416 	.gem_prime_vmap = vgem_prime_vmap,
417 	.gem_prime_vunmap = vgem_prime_vunmap,
418 	.gem_prime_mmap = vgem_prime_mmap,
419 
420 	.name	= DRIVER_NAME,
421 	.desc	= DRIVER_DESC,
422 	.date	= DRIVER_DATE,
423 	.major	= DRIVER_MAJOR,
424 	.minor	= DRIVER_MINOR,
425 };
426 
427 static int __init vgem_init(void)
428 {
429 	int ret;
430 
431 	vgem_device = kzalloc(sizeof(*vgem_device), GFP_KERNEL);
432 	if (!vgem_device)
433 		return -ENOMEM;
434 
435 	ret = drm_dev_init(&vgem_device->drm, &vgem_driver, NULL);
436 	if (ret)
437 		goto out_free;
438 
439 	vgem_device->platform =
440 		platform_device_register_simple("vgem", -1, NULL, 0);
441 	if (!vgem_device->platform) {
442 		ret = -ENODEV;
443 		goto out_fini;
444 	}
445 
446 	dma_coerce_mask_and_coherent(&vgem_device->platform->dev,
447 				     DMA_BIT_MASK(64));
448 
449 	/* Final step: expose the device/driver to userspace */
450 	ret  = drm_dev_register(&vgem_device->drm, 0);
451 	if (ret)
452 		goto out_unregister;
453 
454 	return 0;
455 
456 out_unregister:
457 	platform_device_unregister(vgem_device->platform);
458 out_fini:
459 	drm_dev_fini(&vgem_device->drm);
460 out_free:
461 	kfree(vgem_device);
462 	return ret;
463 }
464 
465 static void __exit vgem_exit(void)
466 {
467 	drm_dev_unregister(&vgem_device->drm);
468 	drm_dev_unref(&vgem_device->drm);
469 }
470 
471 module_init(vgem_init);
472 module_exit(vgem_exit);
473 
474 MODULE_AUTHOR("Red Hat, Inc.");
475 MODULE_AUTHOR("Intel Corporation");
476 MODULE_DESCRIPTION(DRIVER_DESC);
477 MODULE_LICENSE("GPL and additional rights");
478