From 488c888ae1d4bb7121a2935b5f46aa65bbd62937 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 13 Oct 2020 13:10:27 +0200 Subject: [PATCH] drm/vkms: Switch to shmem helpers Inspired by a patch by Chris Wilson for vgem. Plus this gives us vmap at the gem bo level, which we need for generic fbdev emulation. Luckily shmem also tracks ->vaddr, so we just need to adjust the code all over a bit to make this fit. Also wire up handle_to_fd, dunno why that was missing. v2: - Drop now unused container_of #define (Melissa) - Make sure we keep creating cached objects, this is for testing (Thomas) Signed-off-by: Daniel Vetter Cc: Chris Wilson Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Cc: David Airlie Cc: Daniel Vetter Cc: Rodrigo Siqueira Cc: Melissa Wen Cc: Haneen Mohammed Acked-by: Thomas Zimmermann Reviewed-by: Melissa Wen Link: https://patchwork.freedesktop.org/patch/msgid/20201013111027.375999-1-daniel.vetter@ffwll.ch --- drivers/gpu/drm/Kconfig | 1 + drivers/gpu/drm/vkms/Makefile | 1 - drivers/gpu/drm/vkms/vkms_composer.c | 17 +-- drivers/gpu/drm/vkms/vkms_drv.c | 18 +-- drivers/gpu/drm/vkms/vkms_drv.h | 29 ---- drivers/gpu/drm/vkms/vkms_gem.c | 261 ---------------------------------- drivers/gpu/drm/vkms/vkms_plane.c | 13 +- drivers/gpu/drm/vkms/vkms_writeback.c | 17 ++- 8 files changed, 30 insertions(+), 327 deletions(-) delete mode 100644 drivers/gpu/drm/vkms/vkms_gem.c diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 147d61b..3225718 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -287,6 +287,7 @@ config DRM_VKMS tristate "Virtual KMS (EXPERIMENTAL)" depends on DRM select DRM_KMS_HELPER + select DRM_GEM_SHMEM_HELPER select CRC32 default n help diff --git a/drivers/gpu/drm/vkms/Makefile b/drivers/gpu/drm/vkms/Makefile index 333d3ce..72f779c 100644 --- a/drivers/gpu/drm/vkms/Makefile +++ b/drivers/gpu/drm/vkms/Makefile @@ -4,7 +4,6 @@ vkms-y := \ vkms_plane.o \ vkms_output.o \ vkms_crtc.o \ - vkms_gem.o \ vkms_composer.o \ vkms_writeback.o diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c index 33c031f..66c6842 100644 --- a/drivers/gpu/drm/vkms/vkms_composer.c +++ b/drivers/gpu/drm/vkms/vkms_composer.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "vkms_drv.h" @@ -129,15 +130,15 @@ static void compose_cursor(struct vkms_composer *cursor_composer, void *vaddr_out) { struct drm_gem_object *cursor_obj; - struct vkms_gem_object *cursor_vkms_obj; + struct drm_gem_shmem_object *cursor_shmem_obj; cursor_obj = drm_gem_fb_get_obj(&cursor_composer->fb, 0); - cursor_vkms_obj = drm_gem_to_vkms_gem(cursor_obj); + cursor_shmem_obj = to_drm_gem_shmem_obj(cursor_obj); - if (WARN_ON(!cursor_vkms_obj->vaddr)) + if (WARN_ON(!cursor_shmem_obj->vaddr)) return; - blend(vaddr_out, cursor_vkms_obj->vaddr, + blend(vaddr_out, cursor_shmem_obj->vaddr, primary_composer, cursor_composer); } @@ -147,20 +148,20 @@ static int compose_planes(void **vaddr_out, { struct drm_framebuffer *fb = &primary_composer->fb; struct drm_gem_object *gem_obj = drm_gem_fb_get_obj(fb, 0); - struct vkms_gem_object *vkms_obj = drm_gem_to_vkms_gem(gem_obj); + struct drm_gem_shmem_object *shmem_obj = to_drm_gem_shmem_obj(gem_obj); if (!*vaddr_out) { - *vaddr_out = kzalloc(vkms_obj->gem.size, GFP_KERNEL); + *vaddr_out = kzalloc(shmem_obj->base.size, GFP_KERNEL); if (!*vaddr_out) { DRM_ERROR("Cannot allocate memory for output frame."); return -ENOMEM; } } - if (WARN_ON(!vkms_obj->vaddr)) + if (WARN_ON(!shmem_obj->vaddr)) return -EINVAL; - memcpy(*vaddr_out, vkms_obj->vaddr, vkms_obj->gem.size); + memcpy(*vaddr_out, shmem_obj->vaddr, shmem_obj->base.size); if (cursor_composer) compose_cursor(cursor_composer, primary_composer, *vaddr_out); diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index eb40074..198a894 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "vkms_drv.h" @@ -39,17 +40,7 @@ bool enable_cursor = true; module_param_named(enable_cursor, enable_cursor, bool, 0444); MODULE_PARM_DESC(enable_cursor, "Enable/Disable cursor support"); -static const struct file_operations vkms_driver_fops = { - .owner = THIS_MODULE, - .open = drm_open, - .mmap = drm_gem_mmap, - .unlocked_ioctl = drm_ioctl, - .compat_ioctl = drm_compat_ioctl, - .poll = drm_poll, - .read = drm_read, - .llseek = no_llseek, - .release = drm_release, -}; +DEFINE_DRM_GEM_FOPS(vkms_driver_fops); static void vkms_release(struct drm_device *dev) { @@ -91,9 +82,8 @@ static struct drm_driver vkms_driver = { .driver_features = DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM, .release = vkms_release, .fops = &vkms_driver_fops, - .dumb_create = vkms_dumb_create, - .prime_fd_to_handle = drm_gem_prime_fd_to_handle, - .gem_prime_import_sg_table = vkms_prime_import_sg_table, + .gem_create_object = drm_gem_shmem_create_object_cached, + DRM_GEM_SHMEM_DRIVER_OPS, .name = DRIVER_NAME, .desc = DRIVER_DESC, diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h index 380a8f2..5ed91ff 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -88,23 +88,12 @@ struct vkms_device { 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; - unsigned int vmap_count; - void *vaddr; -}; - #define drm_crtc_to_vkms_output(target) \ container_of(target, struct vkms_output, crtc) #define drm_device_to_vkms_device(target) \ container_of(target, struct vkms_device, drm) -#define drm_gem_to_vkms_gem(target)\ - container_of(target, struct vkms_gem_object, gem) - #define to_vkms_crtc_state(target)\ container_of(target, struct vkms_crtc_state, base) @@ -120,24 +109,6 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index); struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev, enum drm_plane_type type, int index); -/* Gem stuff */ -vm_fault_t 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); - -void vkms_gem_free_object(struct drm_gem_object *obj); - -int vkms_gem_vmap(struct drm_gem_object *obj); - -void vkms_gem_vunmap(struct drm_gem_object *obj); - -/* Prime */ -struct drm_gem_object * -vkms_prime_import_sg_table(struct drm_device *dev, - struct dma_buf_attachment *attach, - struct sg_table *sg); - /* CRC Support */ const char *const *vkms_get_crc_sources(struct drm_crtc *crtc, size_t *count); diff --git a/drivers/gpu/drm/vkms/vkms_gem.c b/drivers/gpu/drm/vkms/vkms_gem.c deleted file mode 100644 index 19a0e26..0000000 --- a/drivers/gpu/drm/vkms/vkms_gem.c +++ /dev/null @@ -1,261 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ - -#include -#include -#include -#include - -#include "vkms_drv.h" - -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 const struct drm_gem_object_funcs vkms_gem_object_funcs = { - .free = vkms_gem_free_object, - .vm_ops = &vkms_gem_vm_ops, -}; - -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); - - obj->gem.funcs = &vkms_gem_object_funcs; - - 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); - - WARN_ON(gem->pages); - WARN_ON(gem->vaddr); - - mutex_destroy(&gem->pages_lock); - drm_gem_object_release(obj); - kfree(gem); -} - -vm_fault_t 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; - vm_fault_t ret = VM_FAULT_SIGBUS; - - 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; - - 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; -} - -static 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); - if (ret) - 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_gem_object_put(gem_obj); - - DRM_DEBUG_DRIVER("Created object of size %lld\n", size); - - return 0; -} - -static struct page **_get_pages(struct vkms_gem_object *vkms_obj) -{ - struct drm_gem_object *gem_obj = &vkms_obj->gem; - - if (!vkms_obj->pages) { - struct page **pages = drm_gem_get_pages(gem_obj); - - if (IS_ERR(pages)) - return pages; - - if (cmpxchg(&vkms_obj->pages, NULL, pages)) - drm_gem_put_pages(gem_obj, pages, false, true); - } - - return vkms_obj->pages; -} - -void vkms_gem_vunmap(struct drm_gem_object *obj) -{ - struct vkms_gem_object *vkms_obj = drm_gem_to_vkms_gem(obj); - - mutex_lock(&vkms_obj->pages_lock); - if (vkms_obj->vmap_count < 1) { - WARN_ON(vkms_obj->vaddr); - WARN_ON(vkms_obj->pages); - mutex_unlock(&vkms_obj->pages_lock); - return; - } - - vkms_obj->vmap_count--; - - if (vkms_obj->vmap_count == 0) { - vunmap(vkms_obj->vaddr); - vkms_obj->vaddr = NULL; - drm_gem_put_pages(obj, vkms_obj->pages, false, true); - vkms_obj->pages = NULL; - } - - mutex_unlock(&vkms_obj->pages_lock); -} - -int vkms_gem_vmap(struct drm_gem_object *obj) -{ - struct vkms_gem_object *vkms_obj = drm_gem_to_vkms_gem(obj); - int ret = 0; - - mutex_lock(&vkms_obj->pages_lock); - - if (!vkms_obj->vaddr) { - unsigned int n_pages = obj->size >> PAGE_SHIFT; - struct page **pages = _get_pages(vkms_obj); - - if (IS_ERR(pages)) { - ret = PTR_ERR(pages); - goto out; - } - - vkms_obj->vaddr = vmap(pages, n_pages, VM_MAP, PAGE_KERNEL); - if (!vkms_obj->vaddr) - goto err_vmap; - } - - vkms_obj->vmap_count++; - goto out; - -err_vmap: - ret = -ENOMEM; - drm_gem_put_pages(obj, vkms_obj->pages, false, true); - vkms_obj->pages = NULL; -out: - mutex_unlock(&vkms_obj->pages_lock); - return ret; -} - -struct drm_gem_object * -vkms_prime_import_sg_table(struct drm_device *dev, - struct dma_buf_attachment *attach, - struct sg_table *sg) -{ - struct vkms_gem_object *obj; - int npages; - - obj = __vkms_gem_create(dev, attach->dmabuf->size); - if (IS_ERR(obj)) - return ERR_CAST(obj); - - npages = PAGE_ALIGN(attach->dmabuf->size) / PAGE_SIZE; - DRM_DEBUG_PRIME("Importing %d pages\n", npages); - - obj->pages = kvmalloc_array(npages, sizeof(struct page *), GFP_KERNEL); - if (!obj->pages) { - vkms_gem_free_object(&obj->gem); - return ERR_PTR(-ENOMEM); - } - - drm_prime_sg_to_page_addr_arrays(sg, obj->pages, NULL, npages); - return &obj->gem; -} diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c index 6d31265..9890137 100644 --- a/drivers/gpu/drm/vkms/vkms_plane.c +++ b/drivers/gpu/drm/vkms/vkms_plane.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "vkms_drv.h" @@ -145,15 +146,15 @@ static int vkms_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state) { struct drm_gem_object *gem_obj; - int ret; + void *vaddr; if (!state->fb) return 0; gem_obj = drm_gem_fb_get_obj(state->fb, 0); - ret = vkms_gem_vmap(gem_obj); - if (ret) - DRM_ERROR("vmap failed: %d\n", ret); + vaddr = drm_gem_shmem_vmap(gem_obj); + if (IS_ERR(vaddr)) + DRM_ERROR("vmap failed: %li\n", PTR_ERR(vaddr)); return drm_gem_fb_prepare_fb(plane, state); } @@ -162,12 +163,14 @@ static void vkms_cleanup_fb(struct drm_plane *plane, struct drm_plane_state *old_state) { struct drm_gem_object *gem_obj; + struct drm_gem_shmem_object *shmem_obj; if (!old_state->fb) return; gem_obj = drm_gem_fb_get_obj(old_state->fb, 0); - vkms_gem_vunmap(gem_obj); + shmem_obj = to_drm_gem_shmem_obj(drm_gem_fb_get_obj(old_state->fb, 0)); + drm_gem_shmem_vunmap(gem_obj, shmem_obj->vaddr); } static const struct drm_plane_helper_funcs vkms_primary_helper_funcs = { diff --git a/drivers/gpu/drm/vkms/vkms_writeback.c b/drivers/gpu/drm/vkms/vkms_writeback.c index 094fa4a..26b9039 100644 --- a/drivers/gpu/drm/vkms/vkms_writeback.c +++ b/drivers/gpu/drm/vkms/vkms_writeback.c @@ -6,6 +6,7 @@ #include #include #include +#include static const u32 vkms_wb_formats[] = { DRM_FORMAT_XRGB8888, @@ -63,22 +64,20 @@ static int vkms_wb_connector_get_modes(struct drm_connector *connector) static int vkms_wb_prepare_job(struct drm_writeback_connector *wb_connector, struct drm_writeback_job *job) { - struct vkms_gem_object *vkms_obj; struct drm_gem_object *gem_obj; - int ret; + void *vaddr; if (!job->fb) return 0; gem_obj = drm_gem_fb_get_obj(job->fb, 0); - ret = vkms_gem_vmap(gem_obj); - if (ret) { - DRM_ERROR("vmap failed: %d\n", ret); - return ret; + vaddr = drm_gem_shmem_vmap(gem_obj); + if (IS_ERR(vaddr)) { + DRM_ERROR("vmap failed: %li\n", PTR_ERR(vaddr)); + return PTR_ERR(vaddr); } - vkms_obj = drm_gem_to_vkms_gem(gem_obj); - job->priv = vkms_obj->vaddr; + job->priv = vaddr; return 0; } @@ -93,7 +92,7 @@ static void vkms_wb_cleanup_job(struct drm_writeback_connector *connector, return; gem_obj = drm_gem_fb_get_obj(job->fb, 0); - vkms_gem_vunmap(gem_obj); + drm_gem_shmem_vunmap(gem_obj, job->priv); vkmsdev = drm_device_to_vkms_device(gem_obj->dev); vkms_set_composer(&vkmsdev->output, false); -- 2.7.4