Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions drivers/gpu/drm/drm_framebuffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -844,11 +844,23 @@ void drm_framebuffer_free(struct kref *kref)
int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
const struct drm_framebuffer_funcs *funcs)
{
unsigned int i;
int ret;
bool exists;

if (WARN_ON_ONCE(fb->dev != dev || !fb->format))
return -EINVAL;

for (i = 0; i < fb->format->num_planes; i++) {
if (drm_WARN_ON_ONCE(dev, fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i)))
fb->internal_flags &= ~DRM_FRAMEBUFFER_HAS_HANDLE_REF(i);
if (fb->obj[i]) {
exists = drm_gem_object_handle_get_if_exists_unlocked(fb->obj[i]);
if (exists)
fb->internal_flags |= DRM_FRAMEBUFFER_HAS_HANDLE_REF(i);
}
}

INIT_LIST_HEAD(&fb->filp_head);

fb->funcs = funcs;
Expand All @@ -857,15 +869,24 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
ret = __drm_mode_object_add(dev, &fb->base, DRM_MODE_OBJECT_FB,
false, drm_framebuffer_free);
if (ret)
goto out;
goto err;

mutex_lock(&dev->mode_config.fb_lock);
dev->mode_config.num_fb++;
list_add(&fb->head, &dev->mode_config.fb_list);
mutex_unlock(&dev->mode_config.fb_lock);

drm_mode_object_register(dev, &fb->base);
out:

return 0;

err:
for (i = 0; i < fb->format->num_planes; i++) {
if (fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i)) {
drm_gem_object_handle_put_unlocked(fb->obj[i]);
fb->internal_flags &= ~DRM_FRAMEBUFFER_HAS_HANDLE_REF(i);
}
}
return ret;
}
EXPORT_SYMBOL(drm_framebuffer_init);
Expand Down Expand Up @@ -942,6 +963,12 @@ EXPORT_SYMBOL(drm_framebuffer_unregister_private);
void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
{
struct drm_device *dev = fb->dev;
unsigned int i;

for (i = 0; i < fb->format->num_planes; i++) {
if (fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i))
drm_gem_object_handle_put_unlocked(fb->obj[i]);
}

mutex_lock(&dev->mode_config.fb_lock);
list_del(&fb->head);
Expand Down
86 changes: 74 additions & 12 deletions drivers/gpu/drm/drm_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,63 @@ void drm_gem_private_object_init(struct drm_device *dev,
}
EXPORT_SYMBOL(drm_gem_private_object_init);

/**
* drm_gem_private_object_fini - Finalize a failed drm_gem_object
* @obj: drm_gem_object
*
* Uninitialize an already allocated GEM object when it initialized failed
*/
void drm_gem_private_object_fini(struct drm_gem_object *obj)
{
WARN_ON(obj->dma_buf);

dma_resv_fini(&obj->_resv);
}
EXPORT_SYMBOL(drm_gem_private_object_fini);

static void drm_gem_object_handle_get(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;

drm_WARN_ON(dev, !mutex_is_locked(&dev->object_name_lock));

if (obj->handle_count++ == 0)
drm_gem_object_get(obj);
}

/**
* drm_gem_object_handle_get_if_exists_unlocked - acquire reference on user-space handle, if any
* @obj: GEM object
*
* Acquires a reference on the GEM buffer object's handle. Required to keep
* the GEM object alive. Call drm_gem_object_handle_put_if_exists_unlocked()
* to release the reference. Does nothing if the buffer object has no handle.
*
* Returns:
* True if a handle exists, or false otherwise
*/
bool drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;

mutex_lock(&dev->object_name_lock);

/*
* First ref taken during GEM object creation, if any. Some
* drivers set up internal framebuffers with GEM objects that
* do not have a GEM handle. Hence, this counter can be zero.
*/
if (!obj->handle_count) {
mutex_unlock(&dev->object_name_lock);
return false;
}

drm_gem_object_handle_get(obj);

mutex_unlock(&dev->object_name_lock);
return true;
}

/**
* drm_gem_object_handle_free - release resources bound to userspace handles
* @obj: GEM object to clean up.
Expand Down Expand Up @@ -198,20 +255,26 @@ static void drm_gem_object_exported_dma_buf_free(struct drm_gem_object *obj)
}
}

static void
drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
/**
* drm_gem_object_handle_put_unlocked - releases reference on user-space handle
* @obj: GEM object
*
* Releases a reference on the GEM buffer object's handle. Possibly releases
* the GEM buffer object and associated dma-buf objects.
*/
void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
bool final = false;

if (WARN_ON(READ_ONCE(obj->handle_count) == 0))
if (drm_WARN_ON(dev, READ_ONCE(obj->handle_count) == 0))
return;

/*
* Must bump handle count first as this may be the last
* ref, in which case the object would disappear before we
* checked for a name
*/
* Must bump handle count first as this may be the last
* ref, in which case the object would disappear before
* we checked for a name.
*/

mutex_lock(&dev->object_name_lock);
if (--obj->handle_count == 0) {
Expand Down Expand Up @@ -352,8 +415,8 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,
int ret;

WARN_ON(!mutex_is_locked(&dev->object_name_lock));
if (obj->handle_count++ == 0)
drm_gem_object_get(obj);

drm_gem_object_handle_get(obj);

/*
* Get the user-visible handle using idr. Preload and perform
Expand Down Expand Up @@ -929,12 +992,11 @@ drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
void
drm_gem_object_release(struct drm_gem_object *obj)
{
WARN_ON(obj->dma_buf);

if (obj->filp)
fput(obj->filp);

dma_resv_fini(&obj->_resv);
drm_gem_private_object_fini(obj);

drm_gem_free_mmap_offset(obj);
}
EXPORT_SYMBOL(drm_gem_object_release);
Expand Down
4 changes: 3 additions & 1 deletion drivers/gpu/drm/drm_gem_shmem_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,10 @@ __drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private)
} else {
ret = drm_gem_object_init(dev, obj, size);
}
if (ret)
if (ret) {
drm_gem_private_object_fini(obj);
goto err_free;
}

ret = drm_gem_create_mmap_offset(obj);
if (ret)
Expand Down
2 changes: 2 additions & 0 deletions drivers/gpu/drm/drm_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ void drm_sysfs_lease_event(struct drm_device *dev);

/* drm_gem.c */
int drm_gem_init(struct drm_device *dev);
bool drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj);
void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj);
int drm_gem_handle_create_tail(struct drm_file *file_priv,
struct drm_gem_object *obj,
u32 *handlep);
Expand Down
7 changes: 7 additions & 0 deletions include/drm/drm_framebuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#ifndef __DRM_FRAMEBUFFER_H__
#define __DRM_FRAMEBUFFER_H__

#include <linux/bits.h>
#include <linux/ctype.h>
#include <linux/list.h>
#include <linux/sched.h>
Expand Down Expand Up @@ -100,6 +101,8 @@ struct drm_framebuffer_funcs {
unsigned num_clips);
};

#define DRM_FRAMEBUFFER_HAS_HANDLE_REF(_i) BIT(0u + (_i))

/**
* struct drm_framebuffer - frame buffer object
*
Expand Down Expand Up @@ -188,6 +191,10 @@ struct drm_framebuffer {
* DRM_MODE_FB_MODIFIERS.
*/
int flags;
/**
* @internal_flags: Framebuffer flags like DRM_FRAMEBUFFER_HAS_HANDLE_REF.
*/
unsigned int internal_flags;
/**
* @hot_x: X coordinate of the cursor hotspot. Used by the legacy cursor
* IOCTL when the driver supports cursor through a DRM_PLANE_TYPE_CURSOR
Expand Down
1 change: 1 addition & 0 deletions include/drm/drm_gem.h
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ int drm_gem_object_init(struct drm_device *dev,
struct drm_gem_object *obj, size_t size);
void drm_gem_private_object_init(struct drm_device *dev,
struct drm_gem_object *obj, size_t size);
void drm_gem_private_object_fini(struct drm_gem_object *obj);
void drm_gem_vm_open(struct vm_area_struct *vma);
void drm_gem_vm_close(struct vm_area_struct *vma);
int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
Expand Down