forked from mirrors/linux
		
	drm/vkms: Add dumb operations
VKMS currently does not handle dumb data, and as a consequence, it does not provide mechanisms for handling gem. This commit adds the necessary support for gem object/handler and the dumb functions. Changes since V1: Daniel Vetter: - Add dumb buffer support to the same patchset Changes since V2: Haneen: - Add missing gem_free_object_unlocked callback to fix the warning "Memory manager not clean during takedown" Signed-off-by: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/70b7becc91c6a323dbc15cb5fc912cbdfe4ef7d9.1531359228.git.rodrigosiqueiramelo@gmail.com
This commit is contained in:
		
							parent
							
								
									ae61f61fa8
								
							
						
					
					
						commit
						559e50fd34
					
				
					 4 changed files with 213 additions and 1 deletions
				
			
		| 
						 | 
					@ -1,3 +1,3 @@
 | 
				
			||||||
vkms-y := vkms_drv.o vkms_plane.o vkms_output.o vkms_crtc.o
 | 
					vkms-y := vkms_drv.o vkms_plane.o vkms_output.o vkms_crtc.o vkms_gem.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
obj-$(CONFIG_DRM_VKMS) += vkms.o
 | 
					obj-$(CONFIG_DRM_VKMS) += vkms.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,6 +37,12 @@ static const struct file_operations vkms_driver_fops = {
 | 
				
			||||||
	.release	= drm_release,
 | 
						.release	= drm_release,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct vm_operations_struct vkms_gem_vm_ops = {
 | 
				
			||||||
 | 
						.fault = vkms_gem_fault,
 | 
				
			||||||
 | 
						.open = drm_gem_vm_open,
 | 
				
			||||||
 | 
						.close = drm_gem_vm_close,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void vkms_release(struct drm_device *dev)
 | 
					static void vkms_release(struct drm_device *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct vkms_device *vkms = container_of(dev, struct vkms_device, drm);
 | 
						struct vkms_device *vkms = container_of(dev, struct vkms_device, drm);
 | 
				
			||||||
| 
						 | 
					@ -50,6 +56,10 @@ static struct drm_driver vkms_driver = {
 | 
				
			||||||
	.driver_features	= DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM,
 | 
						.driver_features	= DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM,
 | 
				
			||||||
	.release		= vkms_release,
 | 
						.release		= vkms_release,
 | 
				
			||||||
	.fops			= &vkms_driver_fops,
 | 
						.fops			= &vkms_driver_fops,
 | 
				
			||||||
 | 
						.dumb_create		= vkms_dumb_create,
 | 
				
			||||||
 | 
						.dumb_map_offset	= vkms_dumb_map,
 | 
				
			||||||
 | 
						.gem_vm_ops		= &vkms_gem_vm_ops,
 | 
				
			||||||
 | 
						.gem_free_object_unlocked = vkms_gem_free_object,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	.name			= DRIVER_NAME,
 | 
						.name			= DRIVER_NAME,
 | 
				
			||||||
	.desc			= DRIVER_DESC,
 | 
						.desc			= DRIVER_DESC,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <drm/drmP.h>
 | 
					#include <drm/drmP.h>
 | 
				
			||||||
#include <drm/drm.h>
 | 
					#include <drm/drm.h>
 | 
				
			||||||
 | 
					#include <drm/drm_gem.h>
 | 
				
			||||||
#include <drm/drm_encoder.h>
 | 
					#include <drm/drm_encoder.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const u32 vkms_formats[] = {
 | 
					static const u32 vkms_formats[] = {
 | 
				
			||||||
| 
						 | 
					@ -21,6 +22,12 @@ struct vkms_device {
 | 
				
			||||||
	struct vkms_output output;
 | 
						struct vkms_output output;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct vkms_gem_object {
 | 
				
			||||||
 | 
						struct drm_gem_object gem;
 | 
				
			||||||
 | 
						struct mutex pages_lock; /* Page lock used in page fault handler */
 | 
				
			||||||
 | 
						struct page **pages;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 | 
					int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 | 
				
			||||||
		   struct drm_plane *primary, struct drm_plane *cursor);
 | 
							   struct drm_plane *primary, struct drm_plane *cursor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,4 +35,20 @@ int vkms_output_init(struct vkms_device *vkmsdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev);
 | 
					struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Gem stuff */
 | 
				
			||||||
 | 
					struct drm_gem_object *vkms_gem_create(struct drm_device *dev,
 | 
				
			||||||
 | 
									       struct drm_file *file,
 | 
				
			||||||
 | 
									       u32 *handle,
 | 
				
			||||||
 | 
									       u64 size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int vkms_gem_fault(struct vm_fault *vmf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int vkms_dumb_create(struct drm_file *file, struct drm_device *dev,
 | 
				
			||||||
 | 
							     struct drm_mode_create_dumb *args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int vkms_dumb_map(struct drm_file *file, struct drm_device *dev,
 | 
				
			||||||
 | 
							  u32 handle, u64 *offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void vkms_gem_free_object(struct drm_gem_object *obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _VKMS_DRV_H_ */
 | 
					#endif /* _VKMS_DRV_H_ */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										179
									
								
								drivers/gpu/drm/vkms/vkms_gem.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								drivers/gpu/drm/vkms/vkms_gem.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,179 @@
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: GPL-2.0
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation; either version 2 of the License, or
 | 
				
			||||||
 | 
					 * (at your option) any later version.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/shmem_fs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "vkms_drv.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct vkms_gem_object *__vkms_gem_create(struct drm_device *dev,
 | 
				
			||||||
 | 
											 u64 size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct vkms_gem_object *obj;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						obj = kzalloc(sizeof(*obj), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!obj)
 | 
				
			||||||
 | 
							return ERR_PTR(-ENOMEM);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						size = roundup(size, PAGE_SIZE);
 | 
				
			||||||
 | 
						ret = drm_gem_object_init(dev, &obj->gem, size);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							kfree(obj);
 | 
				
			||||||
 | 
							return ERR_PTR(ret);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_init(&obj->pages_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return obj;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void vkms_gem_free_object(struct drm_gem_object *obj)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct vkms_gem_object *gem = container_of(obj, struct vkms_gem_object,
 | 
				
			||||||
 | 
											   gem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						kvfree(gem->pages);
 | 
				
			||||||
 | 
						mutex_destroy(&gem->pages_lock);
 | 
				
			||||||
 | 
						drm_gem_object_release(obj);
 | 
				
			||||||
 | 
						kfree(gem);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int vkms_gem_fault(struct vm_fault *vmf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct vm_area_struct *vma = vmf->vma;
 | 
				
			||||||
 | 
						struct vkms_gem_object *obj = vma->vm_private_data;
 | 
				
			||||||
 | 
						unsigned long vaddr = vmf->address;
 | 
				
			||||||
 | 
						pgoff_t page_offset;
 | 
				
			||||||
 | 
						loff_t num_pages;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						page_offset = (vaddr - vma->vm_start) >> PAGE_SHIFT;
 | 
				
			||||||
 | 
						num_pages = DIV_ROUND_UP(obj->gem.size, PAGE_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (page_offset > num_pages)
 | 
				
			||||||
 | 
							return VM_FAULT_SIGBUS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = -ENOENT;
 | 
				
			||||||
 | 
						mutex_lock(&obj->pages_lock);
 | 
				
			||||||
 | 
						if (obj->pages) {
 | 
				
			||||||
 | 
							get_page(obj->pages[page_offset]);
 | 
				
			||||||
 | 
							vmf->page = obj->pages[page_offset];
 | 
				
			||||||
 | 
							ret = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						mutex_unlock(&obj->pages_lock);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							struct page *page;
 | 
				
			||||||
 | 
							struct address_space *mapping;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							mapping = file_inode(obj->gem.filp)->i_mapping;
 | 
				
			||||||
 | 
							page = shmem_read_mapping_page(mapping, page_offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!IS_ERR(page)) {
 | 
				
			||||||
 | 
								vmf->page = page;
 | 
				
			||||||
 | 
								ret = 0;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								switch (PTR_ERR(page)) {
 | 
				
			||||||
 | 
								case -ENOSPC:
 | 
				
			||||||
 | 
								case -ENOMEM:
 | 
				
			||||||
 | 
									ret = VM_FAULT_OOM;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								case -EBUSY:
 | 
				
			||||||
 | 
									ret = VM_FAULT_RETRY;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								case -EFAULT:
 | 
				
			||||||
 | 
								case -EINVAL:
 | 
				
			||||||
 | 
									ret = VM_FAULT_SIGBUS;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									WARN_ON(PTR_ERR(page));
 | 
				
			||||||
 | 
									ret = VM_FAULT_SIGBUS;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct drm_gem_object *vkms_gem_create(struct drm_device *dev,
 | 
				
			||||||
 | 
									       struct drm_file *file,
 | 
				
			||||||
 | 
									       u32 *handle,
 | 
				
			||||||
 | 
									       u64 size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct vkms_gem_object *obj;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!file || !dev || !handle)
 | 
				
			||||||
 | 
							return ERR_PTR(-EINVAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						obj = __vkms_gem_create(dev, size);
 | 
				
			||||||
 | 
						if (IS_ERR(obj))
 | 
				
			||||||
 | 
							return ERR_CAST(obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = drm_gem_handle_create(file, &obj->gem, handle);
 | 
				
			||||||
 | 
						drm_gem_object_put_unlocked(&obj->gem);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							drm_gem_object_release(&obj->gem);
 | 
				
			||||||
 | 
							kfree(obj);
 | 
				
			||||||
 | 
							return ERR_PTR(ret);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &obj->gem;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int vkms_dumb_create(struct drm_file *file, struct drm_device *dev,
 | 
				
			||||||
 | 
							     struct drm_mode_create_dumb *args)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct drm_gem_object *gem_obj;
 | 
				
			||||||
 | 
						u64 pitch, size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!args || !dev || !file)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pitch = args->width * DIV_ROUND_UP(args->bpp, 8);
 | 
				
			||||||
 | 
						size = pitch * args->height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!size)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gem_obj = vkms_gem_create(dev, file, &args->handle, size);
 | 
				
			||||||
 | 
						if (IS_ERR(gem_obj))
 | 
				
			||||||
 | 
							return PTR_ERR(gem_obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						args->size = gem_obj->size;
 | 
				
			||||||
 | 
						args->pitch = pitch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						DRM_DEBUG_DRIVER("Created object of size %lld\n", size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int vkms_dumb_map(struct drm_file *file, struct drm_device *dev,
 | 
				
			||||||
 | 
							  u32 handle, u64 *offset)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct drm_gem_object *obj;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						obj = drm_gem_object_lookup(file, handle);
 | 
				
			||||||
 | 
						if (!obj)
 | 
				
			||||||
 | 
							return -ENOENT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!obj->filp) {
 | 
				
			||||||
 | 
							ret = -EINVAL;
 | 
				
			||||||
 | 
							goto unref;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = drm_gem_create_mmap_offset(obj);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							goto unref;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*offset = drm_vma_node_offset_addr(&obj->vma_node);
 | 
				
			||||||
 | 
					unref:
 | 
				
			||||||
 | 
						drm_gem_object_put_unlocked(obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in a new issue