Commit b39b5394 authored by Noralf Trønnes's avatar Noralf Trønnes

drm/gem: Add drm_gem_object_funcs

This adds an optional function table on GEM objects.
The main benefit is for drivers that support more than one type of
memory (shmem,vram,cma) for their buffers depending on the hardware it
runs on. With the callbacks attached to the GEM object itself, it is
easier to have core helpers for the the various buffer types. The driver
only has to make the decision about buffer type on GEM object creation
and all other callbacks can be handled by the chosen helper.

drm_driver->gem_prime_res_obj has not been added since there's a todo to
put a reservation_object into drm_gem_object.

v3: Add todo entry

v2: Drop drm_gem_object_funcs->prime_mmap in favour of
drm_gem_prime_mmap() (Daniel Vetter)

v1:
- drm_gem_object_funcs.map -> .prime_map let it only do PRIME mmap like
  the function it superseeds (Daniel Vetter)
- Flip around the if ladders and make obj->funcs the first choice
  highlighting the fact that this the new default way of doing it
  (Daniel Vetter)
Signed-off-by: default avatarNoralf Trønnes <noralf@tronnes.org>
Acked-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Acked-by: default avatarChristian König <christian.koenig@amd.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20181110145647.17580-4-noralf@tronnes.org
parent 7698799f
...@@ -241,6 +241,12 @@ Most drivers don't need to set drm_driver->gem_prime_import and ...@@ -241,6 +241,12 @@ Most drivers don't need to set drm_driver->gem_prime_import and
->gem_prime_export now that drm_gem_prime_import() and drm_gem_prime_export() ->gem_prime_export now that drm_gem_prime_import() and drm_gem_prime_export()
are the default. are the default.
struct drm_gem_object_funcs
---------------------------
GEM objects can now have a function table instead of having the callbacks on the
DRM driver struct. This is now the preferred way and drivers can be moved over.
Core refactorings Core refactorings
================= =================
......
...@@ -81,8 +81,7 @@ int drm_client_init(struct drm_device *dev, struct drm_client_dev *client, ...@@ -81,8 +81,7 @@ int drm_client_init(struct drm_device *dev, struct drm_client_dev *client,
{ {
int ret; int ret;
if (!drm_core_check_feature(dev, DRIVER_MODESET) || if (!drm_core_check_feature(dev, DRIVER_MODESET) || !dev->driver->dumb_create)
!dev->driver->dumb_create || !dev->driver->gem_prime_vmap)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (funcs && !try_module_get(funcs->owner)) if (funcs && !try_module_get(funcs->owner))
...@@ -229,8 +228,7 @@ static void drm_client_buffer_delete(struct drm_client_buffer *buffer) ...@@ -229,8 +228,7 @@ static void drm_client_buffer_delete(struct drm_client_buffer *buffer)
{ {
struct drm_device *dev = buffer->client->dev; struct drm_device *dev = buffer->client->dev;
if (buffer->vaddr && dev->driver->gem_prime_vunmap) drm_gem_vunmap(buffer->gem, buffer->vaddr);
dev->driver->gem_prime_vunmap(buffer->gem, buffer->vaddr);
if (buffer->gem) if (buffer->gem)
drm_gem_object_put_unlocked(buffer->gem); drm_gem_object_put_unlocked(buffer->gem);
...@@ -283,9 +281,9 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u ...@@ -283,9 +281,9 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u
* fd_install step out of the driver backend hooks, to make that * fd_install step out of the driver backend hooks, to make that
* final step optional for internal users. * final step optional for internal users.
*/ */
vaddr = dev->driver->gem_prime_vmap(obj); vaddr = drm_gem_vmap(obj);
if (!vaddr) { if (IS_ERR(vaddr)) {
ret = -ENOMEM; ret = PTR_ERR(vaddr);
goto err_delete; goto err_delete;
} }
......
...@@ -257,7 +257,9 @@ drm_gem_object_release_handle(int id, void *ptr, void *data) ...@@ -257,7 +257,9 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)
struct drm_gem_object *obj = ptr; struct drm_gem_object *obj = ptr;
struct drm_device *dev = obj->dev; struct drm_device *dev = obj->dev;
if (dev->driver->gem_close_object) if (obj->funcs && obj->funcs->close)
obj->funcs->close(obj, file_priv);
else if (dev->driver->gem_close_object)
dev->driver->gem_close_object(obj, file_priv); dev->driver->gem_close_object(obj, file_priv);
if (drm_core_check_feature(dev, DRIVER_PRIME)) if (drm_core_check_feature(dev, DRIVER_PRIME))
...@@ -410,7 +412,11 @@ drm_gem_handle_create_tail(struct drm_file *file_priv, ...@@ -410,7 +412,11 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,
if (ret) if (ret)
goto err_remove; goto err_remove;
if (dev->driver->gem_open_object) { if (obj->funcs && obj->funcs->open) {
ret = obj->funcs->open(obj, file_priv);
if (ret)
goto err_revoke;
} else if (dev->driver->gem_open_object) {
ret = dev->driver->gem_open_object(obj, file_priv); ret = dev->driver->gem_open_object(obj, file_priv);
if (ret) if (ret)
goto err_revoke; goto err_revoke;
...@@ -835,7 +841,9 @@ drm_gem_object_free(struct kref *kref) ...@@ -835,7 +841,9 @@ drm_gem_object_free(struct kref *kref)
container_of(kref, struct drm_gem_object, refcount); container_of(kref, struct drm_gem_object, refcount);
struct drm_device *dev = obj->dev; struct drm_device *dev = obj->dev;
if (dev->driver->gem_free_object_unlocked) { if (obj->funcs) {
obj->funcs->free(obj);
} else if (dev->driver->gem_free_object_unlocked) {
dev->driver->gem_free_object_unlocked(obj); dev->driver->gem_free_object_unlocked(obj);
} else if (dev->driver->gem_free_object) { } else if (dev->driver->gem_free_object) {
WARN_ON(!mutex_is_locked(&dev->struct_mutex)); WARN_ON(!mutex_is_locked(&dev->struct_mutex));
...@@ -864,13 +872,13 @@ drm_gem_object_put_unlocked(struct drm_gem_object *obj) ...@@ -864,13 +872,13 @@ drm_gem_object_put_unlocked(struct drm_gem_object *obj)
dev = obj->dev; dev = obj->dev;
if (dev->driver->gem_free_object_unlocked) { if (dev->driver->gem_free_object) {
kref_put(&obj->refcount, drm_gem_object_free);
} else {
might_lock(&dev->struct_mutex); might_lock(&dev->struct_mutex);
if (kref_put_mutex(&obj->refcount, drm_gem_object_free, if (kref_put_mutex(&obj->refcount, drm_gem_object_free,
&dev->struct_mutex)) &dev->struct_mutex))
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
} else {
kref_put(&obj->refcount, drm_gem_object_free);
} }
} }
EXPORT_SYMBOL(drm_gem_object_put_unlocked); EXPORT_SYMBOL(drm_gem_object_put_unlocked);
...@@ -960,11 +968,14 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size, ...@@ -960,11 +968,14 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
if (obj_size < vma->vm_end - vma->vm_start) if (obj_size < vma->vm_end - vma->vm_start)
return -EINVAL; return -EINVAL;
if (!dev->driver->gem_vm_ops) if (obj->funcs && obj->funcs->vm_ops)
vma->vm_ops = obj->funcs->vm_ops;
else if (dev->driver->gem_vm_ops)
vma->vm_ops = dev->driver->gem_vm_ops;
else
return -EINVAL; return -EINVAL;
vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP; vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
vma->vm_ops = dev->driver->gem_vm_ops;
vma->vm_private_data = obj; vma->vm_private_data = obj;
vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
...@@ -1066,6 +1077,86 @@ void drm_gem_print_info(struct drm_printer *p, unsigned int indent, ...@@ -1066,6 +1077,86 @@ void drm_gem_print_info(struct drm_printer *p, unsigned int indent,
drm_printf_indent(p, indent, "imported=%s\n", drm_printf_indent(p, indent, "imported=%s\n",
obj->import_attach ? "yes" : "no"); obj->import_attach ? "yes" : "no");
if (obj->dev->driver->gem_print_info) if (obj->funcs && obj->funcs->print_info)
obj->funcs->print_info(p, indent, obj);
else if (obj->dev->driver->gem_print_info)
obj->dev->driver->gem_print_info(p, indent, obj); obj->dev->driver->gem_print_info(p, indent, obj);
} }
/**
* drm_gem_pin - Pin backing buffer in memory
* @obj: GEM object
*
* Make sure the backing buffer is pinned in memory.
*
* Returns:
* 0 on success or a negative error code on failure.
*/
int drm_gem_pin(struct drm_gem_object *obj)
{
if (obj->funcs && obj->funcs->pin)
return obj->funcs->pin(obj);
else if (obj->dev->driver->gem_prime_pin)
return obj->dev->driver->gem_prime_pin(obj);
else
return 0;
}
EXPORT_SYMBOL(drm_gem_pin);
/**
* drm_gem_unpin - Unpin backing buffer from memory
* @obj: GEM object
*
* Relax the requirement that the backing buffer is pinned in memory.
*/
void drm_gem_unpin(struct drm_gem_object *obj)
{
if (obj->funcs && obj->funcs->unpin)
obj->funcs->unpin(obj);
else if (obj->dev->driver->gem_prime_unpin)
obj->dev->driver->gem_prime_unpin(obj);
}
EXPORT_SYMBOL(drm_gem_unpin);
/**
* drm_gem_vmap - Map buffer into kernel virtual address space
* @obj: GEM object
*
* Returns:
* A virtual pointer to a newly created GEM object or an ERR_PTR-encoded negative
* error code on failure.
*/
void *drm_gem_vmap(struct drm_gem_object *obj)
{
void *vaddr;
if (obj->funcs && obj->funcs->vmap)
vaddr = obj->funcs->vmap(obj);
else if (obj->dev->driver->gem_prime_vmap)
vaddr = obj->dev->driver->gem_prime_vmap(obj);
else
vaddr = ERR_PTR(-EOPNOTSUPP);
if (!vaddr)
vaddr = ERR_PTR(-ENOMEM);
return vaddr;
}
EXPORT_SYMBOL(drm_gem_vmap);
/**
* drm_gem_vunmap - Remove buffer mapping from kernel virtual address space
* @obj: GEM object
* @vaddr: Virtual address (can be NULL)
*/
void drm_gem_vunmap(struct drm_gem_object *obj, void *vaddr)
{
if (!vaddr)
return;
if (obj->funcs && obj->funcs->vunmap)
obj->funcs->vunmap(obj, vaddr);
else if (obj->dev->driver->gem_prime_vunmap)
obj->dev->driver->gem_prime_vunmap(obj, vaddr);
}
EXPORT_SYMBOL(drm_gem_vunmap);
...@@ -199,7 +199,6 @@ int drm_gem_map_attach(struct dma_buf *dma_buf, ...@@ -199,7 +199,6 @@ int drm_gem_map_attach(struct dma_buf *dma_buf,
{ {
struct drm_prime_attachment *prime_attach; struct drm_prime_attachment *prime_attach;
struct drm_gem_object *obj = dma_buf->priv; struct drm_gem_object *obj = dma_buf->priv;
struct drm_device *dev = obj->dev;
prime_attach = kzalloc(sizeof(*prime_attach), GFP_KERNEL); prime_attach = kzalloc(sizeof(*prime_attach), GFP_KERNEL);
if (!prime_attach) if (!prime_attach)
...@@ -208,10 +207,7 @@ int drm_gem_map_attach(struct dma_buf *dma_buf, ...@@ -208,10 +207,7 @@ int drm_gem_map_attach(struct dma_buf *dma_buf,
prime_attach->dir = DMA_NONE; prime_attach->dir = DMA_NONE;
attach->priv = prime_attach; attach->priv = prime_attach;
if (!dev->driver->gem_prime_pin) return drm_gem_pin(obj);
return 0;
return dev->driver->gem_prime_pin(obj);
} }
EXPORT_SYMBOL(drm_gem_map_attach); EXPORT_SYMBOL(drm_gem_map_attach);
...@@ -228,7 +224,6 @@ void drm_gem_map_detach(struct dma_buf *dma_buf, ...@@ -228,7 +224,6 @@ void drm_gem_map_detach(struct dma_buf *dma_buf,
{ {
struct drm_prime_attachment *prime_attach = attach->priv; struct drm_prime_attachment *prime_attach = attach->priv;
struct drm_gem_object *obj = dma_buf->priv; struct drm_gem_object *obj = dma_buf->priv;
struct drm_device *dev = obj->dev;
if (prime_attach) { if (prime_attach) {
struct sg_table *sgt = prime_attach->sgt; struct sg_table *sgt = prime_attach->sgt;
...@@ -247,8 +242,7 @@ void drm_gem_map_detach(struct dma_buf *dma_buf, ...@@ -247,8 +242,7 @@ void drm_gem_map_detach(struct dma_buf *dma_buf,
attach->priv = NULL; attach->priv = NULL;
} }
if (dev->driver->gem_prime_unpin) drm_gem_unpin(obj);
dev->driver->gem_prime_unpin(obj);
} }
EXPORT_SYMBOL(drm_gem_map_detach); EXPORT_SYMBOL(drm_gem_map_detach);
...@@ -310,6 +304,9 @@ struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach, ...@@ -310,6 +304,9 @@ struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
if (WARN_ON(prime_attach->dir != DMA_NONE)) if (WARN_ON(prime_attach->dir != DMA_NONE))
return ERR_PTR(-EBUSY); return ERR_PTR(-EBUSY);
if (obj->funcs)
sgt = obj->funcs->get_sg_table(obj);
else
sgt = obj->dev->driver->gem_prime_get_sg_table(obj); sgt = obj->dev->driver->gem_prime_get_sg_table(obj);
if (!IS_ERR(sgt)) { if (!IS_ERR(sgt)) {
...@@ -406,12 +403,13 @@ EXPORT_SYMBOL(drm_gem_dmabuf_release); ...@@ -406,12 +403,13 @@ EXPORT_SYMBOL(drm_gem_dmabuf_release);
void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf) void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf)
{ {
struct drm_gem_object *obj = dma_buf->priv; struct drm_gem_object *obj = dma_buf->priv;
struct drm_device *dev = obj->dev; void *vaddr;
if (dev->driver->gem_prime_vmap) vaddr = drm_gem_vmap(obj);
return dev->driver->gem_prime_vmap(obj); if (IS_ERR(vaddr))
else vaddr = NULL;
return NULL;
return vaddr;
} }
EXPORT_SYMBOL(drm_gem_dmabuf_vmap); EXPORT_SYMBOL(drm_gem_dmabuf_vmap);
...@@ -426,10 +424,8 @@ EXPORT_SYMBOL(drm_gem_dmabuf_vmap); ...@@ -426,10 +424,8 @@ EXPORT_SYMBOL(drm_gem_dmabuf_vmap);
void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr) void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr)
{ {
struct drm_gem_object *obj = dma_buf->priv; struct drm_gem_object *obj = dma_buf->priv;
struct drm_device *dev = obj->dev;
if (dev->driver->gem_prime_vunmap) drm_gem_vunmap(obj, vaddr);
dev->driver->gem_prime_vunmap(obj, vaddr);
} }
EXPORT_SYMBOL(drm_gem_dmabuf_vunmap); EXPORT_SYMBOL(drm_gem_dmabuf_vunmap);
...@@ -529,7 +525,9 @@ static struct dma_buf *export_and_register_object(struct drm_device *dev, ...@@ -529,7 +525,9 @@ static struct dma_buf *export_and_register_object(struct drm_device *dev,
return dmabuf; return dmabuf;
} }
if (dev->driver->gem_prime_export) if (obj->funcs && obj->funcs->export)
dmabuf = obj->funcs->export(obj, flags);
else if (dev->driver->gem_prime_export)
dmabuf = dev->driver->gem_prime_export(dev, obj, flags); dmabuf = dev->driver->gem_prime_export(dev, obj, flags);
else else
dmabuf = drm_gem_prime_export(dev, obj, flags); dmabuf = drm_gem_prime_export(dev, obj, flags);
......
...@@ -38,6 +38,121 @@ ...@@ -38,6 +38,121 @@
#include <drm/drm_vma_manager.h> #include <drm/drm_vma_manager.h>
struct drm_gem_object;
/**
* struct drm_gem_object_funcs - GEM object functions
*/
struct drm_gem_object_funcs {
/**
* @free:
*
* Deconstructor for drm_gem_objects.
*
* This callback is mandatory.
*/
void (*free)(struct drm_gem_object *obj);
/**
* @open:
*
* Called upon GEM handle creation.
*
* This callback is optional.
*/
int (*open)(struct drm_gem_object *obj, struct drm_file *file);
/**
* @close:
*
* Called upon GEM handle release.
*
* This callback is optional.
*/
void (*close)(struct drm_gem_object *obj, struct drm_file *file);
/**
* @print_info:
*
* If driver subclasses struct &drm_gem_object, it can implement this
* optional hook for printing additional driver specific info.
*
* drm_printf_indent() should be used in the callback passing it the
* indent argument.
*
* This callback is called from drm_gem_print_info().
*
* This callback is optional.
*/
void (*print_info)(struct drm_printer *p, unsigned int indent,
const struct drm_gem_object *obj);
/**
* @export:
*
* Export backing buffer as a &dma_buf.
* If this is not set drm_gem_prime_export() is used.
*
* This callback is optional.
*/
struct dma_buf *(*export)(struct drm_gem_object *obj, int flags);
/**
* @pin:
*
* Pin backing buffer in memory.
*
* This callback is optional.
*/
int (*pin)(struct drm_gem_object *obj);
/**
* @unpin:
*
* Unpin backing buffer.
*
* This callback is optional.
*/
void (*unpin)(struct drm_gem_object *obj);
/**
* @get_sg_table:
*
* Returns a Scatter-Gather table representation of the buffer.
* Used when exporting a buffer.
*
* This callback is mandatory if buffer export is supported.
*/
struct sg_table *(*get_sg_table)(struct drm_gem_object *obj);
/**
* @vmap:
*
* Returns a virtual address for the buffer.
*
* This callback is optional.
*/
void *(*vmap)(struct drm_gem_object *obj);
/**
* @vunmap:
*
* Releases the the address previously returned by @vmap.
*
* This callback is optional.
*/
void (*vunmap)(struct drm_gem_object *obj, void *vaddr);
/**
* @vm_ops:
*
* Virtual memory operations used with mmap.
*
* This is optional but necessary for mmap support.
*/
const struct vm_operations_struct *vm_ops;
};
/** /**
* struct drm_gem_object - GEM buffer object * struct drm_gem_object - GEM buffer object
* *
...@@ -146,6 +261,17 @@ struct drm_gem_object { ...@@ -146,6 +261,17 @@ struct drm_gem_object {
* simply leave it as NULL. * simply leave it as NULL.
*/ */
struct dma_buf_attachment *import_attach; struct dma_buf_attachment *import_attach;
/**
* @funcs:
*
* Optional GEM object functions. If this is set, it will be used instead of the
* corresponding &drm_driver GEM callbacks.
*
* New drivers should use this.
*
*/
const struct drm_gem_object_funcs *funcs;
}; };
/** /**
...@@ -293,4 +419,9 @@ int drm_gem_dumb_destroy(struct drm_file *file, ...@@ -293,4 +419,9 @@ int drm_gem_dumb_destroy(struct drm_file *file,
struct drm_device *dev, struct drm_device *dev,
uint32_t handle); uint32_t handle);
int drm_gem_pin(struct drm_gem_object *obj);
void drm_gem_unpin(struct drm_gem_object *obj);
void *drm_gem_vmap(struct drm_gem_object *obj);
void drm_gem_vunmap(struct drm_gem_object *obj, void *vaddr);
#endif /* __DRM_GEM_H__ */ #endif /* __DRM_GEM_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment