Skip to content
Open
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 @@ -841,11 +841,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 @@ -854,15 +866,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 @@ -939,6 +960,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
69 changes: 60 additions & 9 deletions drivers/gpu/drm/drm_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,51 @@ drm_gem_remove_prime_handles(struct drm_gem_object *obj, struct drm_file *filp)
mutex_unlock(&filp->prime.lock);
}

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 @@ -212,20 +257,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 @@ -366,8 +417,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
35 changes: 2 additions & 33 deletions drivers/gpu/drm/drm_gem_atomic_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -278,10 +278,7 @@ int drm_gem_prepare_shadow_fb(struct drm_plane *plane, struct drm_plane_state *p
{
struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
struct drm_framebuffer *fb = plane_state->fb;
struct drm_gem_object *obj;
struct dma_buf_map map;
int ret;
size_t i;

if (!fb)
return 0;
Expand All @@ -290,27 +287,7 @@ int drm_gem_prepare_shadow_fb(struct drm_plane *plane, struct drm_plane_state *p
if (ret)
return ret;

for (i = 0; i < ARRAY_SIZE(shadow_plane_state->map); ++i) {
obj = drm_gem_fb_get_obj(fb, i);
if (!obj)
continue;
ret = drm_gem_vmap(obj, &map);
if (ret)
goto err_drm_gem_vunmap;
shadow_plane_state->map[i] = map;
}

return 0;

err_drm_gem_vunmap:
while (i) {
--i;
obj = drm_gem_fb_get_obj(fb, i);
if (!obj)
continue;
drm_gem_vunmap(obj, &shadow_plane_state->map[i]);
}
return ret;
return drm_gem_fb_vmap(fb, shadow_plane_state->map, shadow_plane_state->data);
}
EXPORT_SYMBOL(drm_gem_prepare_shadow_fb);

Expand All @@ -328,19 +305,11 @@ void drm_gem_cleanup_shadow_fb(struct drm_plane *plane, struct drm_plane_state *
{
struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
struct drm_framebuffer *fb = plane_state->fb;
size_t i = ARRAY_SIZE(shadow_plane_state->map);
struct drm_gem_object *obj;

if (!fb)
return;

while (i) {
--i;
obj = drm_gem_fb_get_obj(fb, i);
if (!obj)
continue;
drm_gem_vunmap(obj, &shadow_plane_state->map[i]);
}
drm_gem_fb_vunmap(fb, shadow_plane_state->map);
}
EXPORT_SYMBOL(drm_gem_cleanup_shadow_fb);

Expand Down
Loading
Loading