-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
- Loading branch information
Rodrigo Siqueira
authored and
Daniel Vetter
committed
Jul 12, 2018
1 parent
ae61f61
commit 559e50f
Showing
4 changed files
with
213 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} |