mirror of https://gitee.com/openkylin/linux.git
drm/udl: Switch to SHMEM
Udl's GEM code and the generic SHMEM are almost identical. Replace the former with SHMEM. The dmabuf support in udl is being replaced with generic GEM PRIME functions. The main difference is in the caching flags for mmap pages. By default, SHMEM always sets (uncached) write combining. In udl's memory management code, only imported buffers use write combining. Memory pages of locally created buffer objects are mmap'ed with caching enabled. To keep the optimization, udl provides its own mmap function for GEM objects where it fixes up the mapping flags. v3: - restore udl vmap that enables caching v2: - remove obsolete code in a separate patch Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de> Acked-by: Gerd Hoffmann <kraxel@redhat.com> Link: https://patchwork.freedesktop.org/patch/msgid/20191107094307.19870-4-tzimmermann@suse.de
This commit is contained in:
parent
1d48b9e988
commit
08b22f65b3
|
@ -5,6 +5,7 @@ config DRM_UDL
|
|||
depends on USB_SUPPORT
|
||||
depends on USB_ARCH_HAS_HCD
|
||||
select USB
|
||||
select DRM_GEM_SHMEM_HELPER
|
||||
select DRM_KMS_HELPER
|
||||
help
|
||||
This is a KMS driver for the USB displaylink video adapters.
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_file.h>
|
||||
#include <drm/drm_gem_shmem_helper.h>
|
||||
#include <drm/drm_ioctl.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
@ -32,23 +33,7 @@ static int udl_usb_resume(struct usb_interface *interface)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct vm_operations_struct udl_gem_vm_ops = {
|
||||
.fault = udl_gem_fault,
|
||||
.open = drm_gem_vm_open,
|
||||
.close = drm_gem_vm_close,
|
||||
};
|
||||
|
||||
static const struct file_operations udl_driver_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = drm_open,
|
||||
.mmap = udl_drm_gem_mmap,
|
||||
.poll = drm_poll,
|
||||
.read = drm_read,
|
||||
.unlocked_ioctl = drm_ioctl,
|
||||
.release = drm_release,
|
||||
.compat_ioctl = drm_compat_ioctl,
|
||||
.llseek = noop_llseek,
|
||||
};
|
||||
DEFINE_DRM_GEM_FOPS(udl_driver_fops);
|
||||
|
||||
static void udl_driver_release(struct drm_device *dev)
|
||||
{
|
||||
|
@ -63,18 +48,10 @@ static struct drm_driver driver = {
|
|||
.release = udl_driver_release,
|
||||
|
||||
/* gem hooks */
|
||||
.gem_free_object_unlocked = udl_gem_free_object,
|
||||
.gem_create_object = udl_driver_gem_create_object,
|
||||
.gem_vm_ops = &udl_gem_vm_ops,
|
||||
|
||||
.dumb_create = udl_dumb_create,
|
||||
.dumb_map_offset = udl_gem_mmap,
|
||||
.fops = &udl_driver_fops,
|
||||
|
||||
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
|
||||
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
|
||||
.gem_prime_export = udl_gem_prime_export,
|
||||
.gem_prime_import = udl_gem_prime_import,
|
||||
DRM_GEM_SHMEM_DRIVER_OPS,
|
||||
|
||||
.name = DRIVER_NAME,
|
||||
.desc = DRIVER_DESC,
|
||||
|
|
|
@ -85,6 +85,7 @@ struct udl_gem_object {
|
|||
struct udl_framebuffer {
|
||||
struct drm_framebuffer base;
|
||||
struct udl_gem_object *obj;
|
||||
struct drm_gem_shmem_object *shmem;
|
||||
bool active_16; /* active on the 16-bit channel */
|
||||
};
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_gem_shmem_helper.h>
|
||||
#include <drm/drm_modeset_helper.h>
|
||||
|
||||
#include "udl_drv.h"
|
||||
|
@ -94,16 +95,14 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y,
|
|||
if (!fb->active_16)
|
||||
return 0;
|
||||
|
||||
if (!fb->obj->vmapping) {
|
||||
ret = udl_gem_vmap(fb->obj);
|
||||
if (ret == -ENOMEM) {
|
||||
if (!fb->shmem->vaddr) {
|
||||
void *vaddr;
|
||||
|
||||
vaddr = drm_gem_shmem_vmap(&fb->shmem->base);
|
||||
if (IS_ERR(vaddr)) {
|
||||
DRM_ERROR("failed to vmap fb\n");
|
||||
return 0;
|
||||
}
|
||||
if (!fb->obj->vmapping) {
|
||||
DRM_ERROR("failed to vmapping\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
aligned_x = DL_ALIGN_DOWN(x, sizeof(unsigned long));
|
||||
|
@ -127,7 +126,7 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y,
|
|||
const int byte_offset = line_offset + (x << log_bpp);
|
||||
const int dev_byte_offset = (fb->base.width * i + x) << log_bpp;
|
||||
if (udl_render_hline(dev, log_bpp, &urb,
|
||||
(char *) fb->obj->vmapping,
|
||||
(char *) fb->shmem->vaddr,
|
||||
&cmd, byte_offset, dev_byte_offset,
|
||||
width << log_bpp,
|
||||
&bytes_identical, &bytes_sent))
|
||||
|
@ -281,6 +280,7 @@ static int udl_user_framebuffer_dirty(struct drm_framebuffer *fb,
|
|||
unsigned num_clips)
|
||||
{
|
||||
struct udl_framebuffer *ufb = to_udl_fb(fb);
|
||||
struct dma_buf_attachment *import_attach;
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
|
@ -289,8 +289,10 @@ static int udl_user_framebuffer_dirty(struct drm_framebuffer *fb,
|
|||
if (!ufb->active_16)
|
||||
goto unlock;
|
||||
|
||||
if (ufb->obj->base.import_attach) {
|
||||
ret = dma_buf_begin_cpu_access(ufb->obj->base.import_attach->dmabuf,
|
||||
import_attach = ufb->shmem->base.import_attach;
|
||||
|
||||
if (import_attach) {
|
||||
ret = dma_buf_begin_cpu_access(import_attach->dmabuf,
|
||||
DMA_FROM_DEVICE);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
|
@ -304,10 +306,9 @@ static int udl_user_framebuffer_dirty(struct drm_framebuffer *fb,
|
|||
break;
|
||||
}
|
||||
|
||||
if (ufb->obj->base.import_attach) {
|
||||
ret = dma_buf_end_cpu_access(ufb->obj->base.import_attach->dmabuf,
|
||||
if (import_attach)
|
||||
ret = dma_buf_end_cpu_access(import_attach->dmabuf,
|
||||
DMA_FROM_DEVICE);
|
||||
}
|
||||
|
||||
unlock:
|
||||
drm_modeset_unlock_all(fb->dev);
|
||||
|
@ -319,8 +320,8 @@ static void udl_user_framebuffer_destroy(struct drm_framebuffer *fb)
|
|||
{
|
||||
struct udl_framebuffer *ufb = to_udl_fb(fb);
|
||||
|
||||
if (ufb->obj)
|
||||
drm_gem_object_put_unlocked(&ufb->obj->base);
|
||||
if (ufb->shmem)
|
||||
drm_gem_object_put_unlocked(&ufb->shmem->base);
|
||||
|
||||
drm_framebuffer_cleanup(fb);
|
||||
kfree(ufb);
|
||||
|
@ -336,11 +337,11 @@ static int
|
|||
udl_framebuffer_init(struct drm_device *dev,
|
||||
struct udl_framebuffer *ufb,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct udl_gem_object *obj)
|
||||
struct drm_gem_shmem_object *shmem)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ufb->obj = obj;
|
||||
ufb->shmem = shmem;
|
||||
drm_helper_mode_fill_fb_struct(dev, &ufb->base, mode_cmd);
|
||||
ret = drm_framebuffer_init(dev, &ufb->base, &udlfb_funcs);
|
||||
return ret;
|
||||
|
@ -356,7 +357,8 @@ static int udlfb_create(struct drm_fb_helper *helper,
|
|||
struct fb_info *info;
|
||||
struct drm_framebuffer *fb;
|
||||
struct drm_mode_fb_cmd2 mode_cmd;
|
||||
struct udl_gem_object *obj;
|
||||
struct drm_gem_shmem_object *shmem;
|
||||
void *vaddr;
|
||||
uint32_t size;
|
||||
int ret = 0;
|
||||
|
||||
|
@ -373,12 +375,15 @@ static int udlfb_create(struct drm_fb_helper *helper,
|
|||
size = mode_cmd.pitches[0] * mode_cmd.height;
|
||||
size = ALIGN(size, PAGE_SIZE);
|
||||
|
||||
obj = udl_gem_alloc_object(dev, size);
|
||||
if (!obj)
|
||||
shmem = drm_gem_shmem_create(dev, size);
|
||||
if (IS_ERR(shmem)) {
|
||||
ret = PTR_ERR(shmem);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = udl_gem_vmap(obj);
|
||||
if (ret) {
|
||||
vaddr = drm_gem_shmem_vmap(&shmem->base);
|
||||
if (IS_ERR(vaddr)) {
|
||||
ret = PTR_ERR(vaddr);
|
||||
DRM_ERROR("failed to vmap fb\n");
|
||||
goto out_gfree;
|
||||
}
|
||||
|
@ -389,7 +394,7 @@ static int udlfb_create(struct drm_fb_helper *helper,
|
|||
goto out_gfree;
|
||||
}
|
||||
|
||||
ret = udl_framebuffer_init(dev, &ufbdev->ufb, &mode_cmd, obj);
|
||||
ret = udl_framebuffer_init(dev, &ufbdev->ufb, &mode_cmd, shmem);
|
||||
if (ret)
|
||||
goto out_gfree;
|
||||
|
||||
|
@ -397,20 +402,20 @@ static int udlfb_create(struct drm_fb_helper *helper,
|
|||
|
||||
ufbdev->helper.fb = fb;
|
||||
|
||||
info->screen_base = ufbdev->ufb.obj->vmapping;
|
||||
info->screen_base = vaddr;
|
||||
info->fix.smem_len = size;
|
||||
info->fix.smem_start = (unsigned long)ufbdev->ufb.obj->vmapping;
|
||||
info->fix.smem_start = (unsigned long)vaddr;
|
||||
|
||||
info->fbops = &udlfb_ops;
|
||||
drm_fb_helper_fill_info(info, &ufbdev->helper, sizes);
|
||||
|
||||
DRM_DEBUG_KMS("allocated %dx%d vmal %p\n",
|
||||
fb->width, fb->height,
|
||||
ufbdev->ufb.obj->vmapping);
|
||||
ufbdev->ufb.shmem->vaddr);
|
||||
|
||||
return ret;
|
||||
out_gfree:
|
||||
drm_gem_object_put_unlocked(&ufbdev->ufb.obj->base);
|
||||
drm_gem_object_put_unlocked(&ufbdev->ufb.shmem->base);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
@ -424,10 +429,10 @@ static void udl_fbdev_destroy(struct drm_device *dev,
|
|||
{
|
||||
drm_fb_helper_unregister_fbi(&ufbdev->helper);
|
||||
drm_fb_helper_fini(&ufbdev->helper);
|
||||
if (ufbdev->ufb.obj) {
|
||||
if (ufbdev->ufb.shmem) {
|
||||
drm_framebuffer_unregister_private(&ufbdev->ufb.base);
|
||||
drm_framebuffer_cleanup(&ufbdev->ufb.base);
|
||||
drm_gem_object_put_unlocked(&ufbdev->ufb.obj->base);
|
||||
drm_gem_object_put_unlocked(&ufbdev->ufb.shmem->base);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -518,7 +523,8 @@ udl_fb_user_fb_create(struct drm_device *dev,
|
|||
if (ufb == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ret = udl_framebuffer_init(dev, ufb, mode_cmd, to_udl_bo(obj));
|
||||
ret = udl_framebuffer_init(dev, ufb, mode_cmd,
|
||||
to_drm_gem_shmem_obj(obj));
|
||||
if (ret) {
|
||||
kfree(ufb);
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
|
|
@ -7,11 +7,100 @@
|
|||
#include <linux/vmalloc.h>
|
||||
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_gem_shmem_helper.h>
|
||||
#include <drm/drm_mode.h>
|
||||
#include <drm/drm_prime.h>
|
||||
|
||||
#include "udl_drv.h"
|
||||
|
||||
/*
|
||||
* GEM object funcs
|
||||
*/
|
||||
|
||||
static void udl_gem_object_free_object(struct drm_gem_object *obj)
|
||||
{
|
||||
struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
|
||||
|
||||
/* Fbdev emulation vmaps the buffer. Unmap it here for consistency
|
||||
* with the original udl GEM code.
|
||||
*
|
||||
* TODO: Switch to generic fbdev emulation and release the
|
||||
* GEM object with drm_gem_shmem_free_object().
|
||||
*/
|
||||
if (shmem->vaddr)
|
||||
drm_gem_shmem_vunmap(obj, shmem->vaddr);
|
||||
|
||||
drm_gem_shmem_free_object(obj);
|
||||
}
|
||||
|
||||
static int udl_gem_object_mmap(struct drm_gem_object *obj,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = drm_gem_shmem_mmap(obj, vma);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
|
||||
if (obj->import_attach)
|
||||
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
|
||||
vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *udl_gem_object_vmap(struct drm_gem_object *obj)
|
||||
{
|
||||
struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
|
||||
int ret;
|
||||
|
||||
ret = mutex_lock_interruptible(&shmem->vmap_lock);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
if (shmem->vmap_use_count++ > 0)
|
||||
goto out;
|
||||
|
||||
ret = drm_gem_shmem_get_pages(shmem);
|
||||
if (ret)
|
||||
goto err_zero_use;
|
||||
|
||||
if (obj->import_attach)
|
||||
shmem->vaddr = dma_buf_vmap(obj->import_attach->dmabuf);
|
||||
else
|
||||
shmem->vaddr = vmap(shmem->pages, obj->size >> PAGE_SHIFT,
|
||||
VM_MAP, PAGE_KERNEL);
|
||||
|
||||
if (!shmem->vaddr) {
|
||||
DRM_DEBUG_KMS("Failed to vmap pages\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_put_pages;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&shmem->vmap_lock);
|
||||
return shmem->vaddr;
|
||||
|
||||
err_put_pages:
|
||||
drm_gem_shmem_put_pages(shmem);
|
||||
err_zero_use:
|
||||
shmem->vmap_use_count = 0;
|
||||
mutex_unlock(&shmem->vmap_lock);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
static const struct drm_gem_object_funcs udl_gem_object_funcs = {
|
||||
.free = udl_gem_object_free_object,
|
||||
.print_info = drm_gem_shmem_print_info,
|
||||
.pin = drm_gem_shmem_pin,
|
||||
.unpin = drm_gem_shmem_unpin,
|
||||
.get_sg_table = drm_gem_shmem_get_sg_table,
|
||||
.vmap = udl_gem_object_vmap,
|
||||
.vunmap = drm_gem_shmem_vunmap,
|
||||
.mmap = udl_gem_object_mmap,
|
||||
};
|
||||
|
||||
/*
|
||||
* Helpers for struct drm_driver
|
||||
*/
|
||||
|
@ -19,13 +108,17 @@
|
|||
struct drm_gem_object *udl_driver_gem_create_object(struct drm_device *dev,
|
||||
size_t size)
|
||||
{
|
||||
struct udl_gem_object *obj;
|
||||
struct drm_gem_shmem_object *shmem;
|
||||
struct drm_gem_object *obj;
|
||||
|
||||
obj = kzalloc(sizeof(*obj), GFP_KERNEL);
|
||||
if (!obj)
|
||||
shmem = kzalloc(sizeof(*shmem), GFP_KERNEL);
|
||||
if (!shmem)
|
||||
return NULL;
|
||||
|
||||
return &obj->base;
|
||||
obj = &shmem->base;
|
||||
obj->funcs = &udl_gem_object_funcs;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
struct udl_gem_object *udl_gem_alloc_object(struct drm_device *dev,
|
||||
|
|
Loading…
Reference in New Issue