Skip to content

Commit f6bfc9a

Browse files
author
Thomas Zimmermann
committed
drm/framebuffer: Acquire internal references on GEM handles
Acquire GEM handles in drm_framebuffer_init() and release them in the corresponding drm_framebuffer_cleanup(). Ties the handle's lifetime to the framebuffer. Not all GEM buffer objects have GEM handles. If not set, no refcounting takes place. This is the case for some fbdev emulation. This is not a problem as these GEM objects do not use dma-bufs and drivers will not release them while fbdev emulation is running. Framebuffer flags keep a bit per color plane of which the framebuffer holds a GEM handle reference. As all drivers use drm_framebuffer_init(), they will now all hold dma-buf references as fixed in commit 5307dce ("drm/gem: Acquire references on GEM handles for framebuffers"). In the GEM framebuffer helpers, restore the original ref counting on buffer objects. As the helpers for handle refcounting are now no longer called from outside the DRM core, unexport the symbols. v3: - don't mix internal flags with mode flags (Christian) v2: - track framebuffer handle refs by flag - drop gma500 cleanup (Christian) Signed-off-by: Thomas Zimmermann <[email protected]> Fixes: 5307dce ("drm/gem: Acquire references on GEM handles for framebuffers") Reported-by: Bert Karwatzki <[email protected]> Closes: https://lore.kernel.org/dri-devel/[email protected]/ Tested-by: Bert Karwatzki <[email protected]> Tested-by: Mario Limonciello <[email protected]> Tested-by: Borislav Petkov (AMD) <[email protected]> Cc: Thomas Zimmermann <[email protected]> Cc: Anusha Srivatsa <[email protected]> Cc: Christian König <[email protected]> Cc: Maarten Lankhorst <[email protected]> Cc: Maxime Ripard <[email protected]> Cc: Sumit Semwal <[email protected]> Cc: "Christian König" <[email protected]> Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: <[email protected]> Reviewed-by: Christian König <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent d88dfb7 commit f6bfc9a

File tree

5 files changed

+68
-26
lines changed

5 files changed

+68
-26
lines changed

drivers/gpu/drm/drm_framebuffer.c

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -862,11 +862,23 @@ EXPORT_SYMBOL_FOR_TESTS_ONLY(drm_framebuffer_free);
862862
int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
863863
const struct drm_framebuffer_funcs *funcs)
864864
{
865+
unsigned int i;
865866
int ret;
867+
bool exists;
866868

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

872+
for (i = 0; i < fb->format->num_planes; i++) {
873+
if (drm_WARN_ON_ONCE(dev, fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i)))
874+
fb->internal_flags &= ~DRM_FRAMEBUFFER_HAS_HANDLE_REF(i);
875+
if (fb->obj[i]) {
876+
exists = drm_gem_object_handle_get_if_exists_unlocked(fb->obj[i]);
877+
if (exists)
878+
fb->internal_flags |= DRM_FRAMEBUFFER_HAS_HANDLE_REF(i);
879+
}
880+
}
881+
870882
INIT_LIST_HEAD(&fb->filp_head);
871883

872884
fb->funcs = funcs;
@@ -875,15 +887,24 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
875887
ret = __drm_mode_object_add(dev, &fb->base, DRM_MODE_OBJECT_FB,
876888
false, drm_framebuffer_free);
877889
if (ret)
878-
goto out;
890+
goto err;
879891

880892
mutex_lock(&dev->mode_config.fb_lock);
881893
dev->mode_config.num_fb++;
882894
list_add(&fb->head, &dev->mode_config.fb_list);
883895
mutex_unlock(&dev->mode_config.fb_lock);
884896

885897
drm_mode_object_register(dev, &fb->base);
886-
out:
898+
899+
return 0;
900+
901+
err:
902+
for (i = 0; i < fb->format->num_planes; i++) {
903+
if (fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i)) {
904+
drm_gem_object_handle_put_unlocked(fb->obj[i]);
905+
fb->internal_flags &= ~DRM_FRAMEBUFFER_HAS_HANDLE_REF(i);
906+
}
907+
}
887908
return ret;
888909
}
889910
EXPORT_SYMBOL(drm_framebuffer_init);
@@ -960,6 +981,12 @@ EXPORT_SYMBOL(drm_framebuffer_unregister_private);
960981
void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
961982
{
962983
struct drm_device *dev = fb->dev;
984+
unsigned int i;
985+
986+
for (i = 0; i < fb->format->num_planes; i++) {
987+
if (fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i))
988+
drm_gem_object_handle_put_unlocked(fb->obj[i]);
989+
}
963990

964991
mutex_lock(&dev->mode_config.fb_lock);
965992
list_del(&fb->head);

drivers/gpu/drm/drm_gem.c

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -223,23 +223,34 @@ static void drm_gem_object_handle_get(struct drm_gem_object *obj)
223223
}
224224

225225
/**
226-
* drm_gem_object_handle_get_unlocked - acquire reference on user-space handles
226+
* drm_gem_object_handle_get_if_exists_unlocked - acquire reference on user-space handle, if any
227227
* @obj: GEM object
228228
*
229-
* Acquires a reference on the GEM buffer object's handle. Required
230-
* to keep the GEM object alive. Call drm_gem_object_handle_put_unlocked()
231-
* to release the reference.
229+
* Acquires a reference on the GEM buffer object's handle. Required to keep
230+
* the GEM object alive. Call drm_gem_object_handle_put_if_exists_unlocked()
231+
* to release the reference. Does nothing if the buffer object has no handle.
232+
*
233+
* Returns:
234+
* True if a handle exists, or false otherwise
232235
*/
233-
void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj)
236+
bool drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj)
234237
{
235238
struct drm_device *dev = obj->dev;
236239

237240
guard(mutex)(&dev->object_name_lock);
238241

239-
drm_WARN_ON(dev, !obj->handle_count); /* first ref taken in create-tail helper */
242+
/*
243+
* First ref taken during GEM object creation, if any. Some
244+
* drivers set up internal framebuffers with GEM objects that
245+
* do not have a GEM handle. Hence, this counter can be zero.
246+
*/
247+
if (!obj->handle_count)
248+
return false;
249+
240250
drm_gem_object_handle_get(obj);
251+
252+
return true;
241253
}
242-
EXPORT_SYMBOL(drm_gem_object_handle_get_unlocked);
243254

244255
/**
245256
* drm_gem_object_handle_free - release resources bound to userspace handles
@@ -272,7 +283,7 @@ static void drm_gem_object_exported_dma_buf_free(struct drm_gem_object *obj)
272283
}
273284

274285
/**
275-
* drm_gem_object_handle_put_unlocked - releases reference on user-space handles
286+
* drm_gem_object_handle_put_unlocked - releases reference on user-space handle
276287
* @obj: GEM object
277288
*
278289
* Releases a reference on the GEM buffer object's handle. Possibly releases
@@ -283,14 +294,14 @@ void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
283294
struct drm_device *dev = obj->dev;
284295
bool final = false;
285296

286-
if (WARN_ON(READ_ONCE(obj->handle_count) == 0))
297+
if (drm_WARN_ON(dev, READ_ONCE(obj->handle_count) == 0))
287298
return;
288299

289300
/*
290-
* Must bump handle count first as this may be the last
291-
* ref, in which case the object would disappear before we
292-
* checked for a name
293-
*/
301+
* Must bump handle count first as this may be the last
302+
* ref, in which case the object would disappear before
303+
* we checked for a name.
304+
*/
294305

295306
mutex_lock(&dev->object_name_lock);
296307
if (--obj->handle_count == 0) {
@@ -303,7 +314,6 @@ void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
303314
if (final)
304315
drm_gem_object_put(obj);
305316
}
306-
EXPORT_SYMBOL(drm_gem_object_handle_put_unlocked);
307317

308318
/*
309319
* Called at device or object close to release the file's

drivers/gpu/drm/drm_gem_framebuffer_helper.c

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ void drm_gem_fb_destroy(struct drm_framebuffer *fb)
9999
unsigned int i;
100100

101101
for (i = 0; i < fb->format->num_planes; i++)
102-
drm_gem_object_handle_put_unlocked(fb->obj[i]);
102+
drm_gem_object_put(fb->obj[i]);
103103

104104
drm_framebuffer_cleanup(fb);
105105
kfree(fb);
@@ -182,10 +182,8 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
182182
if (!objs[i]) {
183183
drm_dbg_kms(dev, "Failed to lookup GEM object\n");
184184
ret = -ENOENT;
185-
goto err_gem_object_handle_put_unlocked;
185+
goto err_gem_object_put;
186186
}
187-
drm_gem_object_handle_get_unlocked(objs[i]);
188-
drm_gem_object_put(objs[i]);
189187

190188
min_size = (height - 1) * mode_cmd->pitches[i]
191189
+ drm_format_info_min_pitch(info, i, width)
@@ -195,22 +193,22 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
195193
drm_dbg_kms(dev,
196194
"GEM object size (%zu) smaller than minimum size (%u) for plane %d\n",
197195
objs[i]->size, min_size, i);
198-
drm_gem_object_handle_put_unlocked(objs[i]);
196+
drm_gem_object_put(objs[i]);
199197
ret = -EINVAL;
200-
goto err_gem_object_handle_put_unlocked;
198+
goto err_gem_object_put;
201199
}
202200
}
203201

204202
ret = drm_gem_fb_init(dev, fb, mode_cmd, objs, i, funcs);
205203
if (ret)
206-
goto err_gem_object_handle_put_unlocked;
204+
goto err_gem_object_put;
207205

208206
return 0;
209207

210-
err_gem_object_handle_put_unlocked:
208+
err_gem_object_put:
211209
while (i > 0) {
212210
--i;
213-
drm_gem_object_handle_put_unlocked(objs[i]);
211+
drm_gem_object_put(objs[i]);
214212
}
215213
return ret;
216214
}

drivers/gpu/drm/drm_internal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ void drm_sysfs_lease_event(struct drm_device *dev);
161161

162162
/* drm_gem.c */
163163
int drm_gem_init(struct drm_device *dev);
164-
void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj);
164+
bool drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj);
165165
void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj);
166166
int drm_gem_handle_create_tail(struct drm_file *file_priv,
167167
struct drm_gem_object *obj,

include/drm/drm_framebuffer.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#ifndef __DRM_FRAMEBUFFER_H__
2424
#define __DRM_FRAMEBUFFER_H__
2525

26+
#include <linux/bits.h>
2627
#include <linux/ctype.h>
2728
#include <linux/list.h>
2829
#include <linux/sched.h>
@@ -100,6 +101,8 @@ struct drm_framebuffer_funcs {
100101
unsigned num_clips);
101102
};
102103

104+
#define DRM_FRAMEBUFFER_HAS_HANDLE_REF(_i) BIT(0u + (_i))
105+
103106
/**
104107
* struct drm_framebuffer - frame buffer object
105108
*
@@ -188,6 +191,10 @@ struct drm_framebuffer {
188191
* DRM_MODE_FB_MODIFIERS.
189192
*/
190193
int flags;
194+
/**
195+
* @internal_flags: Framebuffer flags like DRM_FRAMEBUFFER_HAS_HANDLE_REF.
196+
*/
197+
unsigned int internal_flags;
191198
/**
192199
* @filp_head: Placed on &drm_file.fbs, protected by &drm_file.fbs_lock.
193200
*/

0 commit comments

Comments
 (0)