aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_crtc.c
diff options
context:
space:
mode:
authorRob Clark <rob@ti.com>2012-09-05 17:48:38 -0400
committerDave Airlie <airlied@redhat.com>2012-10-02 08:15:39 -0400
commitf7eff60ea0e4e35732604e3591e2ff7b3ef41981 (patch)
treea9dd6031479ce9585d7d0af061aa165ed9c5d49b /drivers/gpu/drm/drm_crtc.c
parent33cce6e9801f7d0184a636e9096a7cf7f8237ff9 (diff)
drm: refcnt drm_framebuffer (v4.1)
This simplifies drm fb lifetime, and if the crtc/plane needs to hold a ref to the fb when disabling a pipe until the next vblank, this avoids the need to make disabling an overlay synchronous. This is a problem that shows up when userspace is using a drm plane to implement a hw cursor.. making overlay disable synchronous causes a performance problem when x11 is rapidly enabling/disabling the hw cursor. But not making it synchronous opens up a race condition for crashing if userspace turns around and immediately deletes the fb. Refcnt'ing the fb makes it possible to solve this problem. v1: original v2: add drm_framebuffer_remove() which is called in all paths where fb->funcs->destroy() was directly called before. This cleans up the CRTCs/planes that the fb was attached to. You should only directly use drm_framebuffer_unreference() if you are also using drm_framebuffer_reference() to keep a ref to the fb. v3: add comment explaining the fb refcount v4: remove duplicate 'list_del(&fb->filp_head)' [airlied: v4.1: fix local rejection] Signed-off-by: Rob Clark <rob@ti.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/drm_crtc.c')
-rw-r--r--drivers/gpu/drm/drm_crtc.c79
1 files changed, 67 insertions, 12 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index c418c772a7e5..39afe13a5fa2 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -294,6 +294,8 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
294{ 294{
295 int ret; 295 int ret;
296 296
297 kref_init(&fb->refcount);
298
297 ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB); 299 ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB);
298 if (ret) 300 if (ret)
299 return ret; 301 return ret;
@@ -307,6 +309,38 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
307} 309}
308EXPORT_SYMBOL(drm_framebuffer_init); 310EXPORT_SYMBOL(drm_framebuffer_init);
309 311
312static void drm_framebuffer_free(struct kref *kref)
313{
314 struct drm_framebuffer *fb =
315 container_of(kref, struct drm_framebuffer, refcount);
316 fb->funcs->destroy(fb);
317}
318
319/**
320 * drm_framebuffer_unreference - unref a framebuffer
321 *
322 * LOCKING:
323 * Caller must hold mode config lock.
324 */
325void drm_framebuffer_unreference(struct drm_framebuffer *fb)
326{
327 struct drm_device *dev = fb->dev;
328 DRM_DEBUG("FB ID: %d\n", fb->base.id);
329 WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
330 kref_put(&fb->refcount, drm_framebuffer_free);
331}
332EXPORT_SYMBOL(drm_framebuffer_unreference);
333
334/**
335 * drm_framebuffer_reference - incr the fb refcnt
336 */
337void drm_framebuffer_reference(struct drm_framebuffer *fb)
338{
339 DRM_DEBUG("FB ID: %d\n", fb->base.id);
340 kref_get(&fb->refcount);
341}
342EXPORT_SYMBOL(drm_framebuffer_reference);
343
310/** 344/**
311 * drm_framebuffer_cleanup - remove a framebuffer object 345 * drm_framebuffer_cleanup - remove a framebuffer object
312 * @fb: framebuffer to remove 346 * @fb: framebuffer to remove
@@ -320,6 +354,32 @@ EXPORT_SYMBOL(drm_framebuffer_init);
320void drm_framebuffer_cleanup(struct drm_framebuffer *fb) 354void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
321{ 355{
322 struct drm_device *dev = fb->dev; 356 struct drm_device *dev = fb->dev;
357 /*
358 * This could be moved to drm_framebuffer_remove(), but for
359 * debugging is nice to keep around the list of fb's that are
360 * no longer associated w/ a drm_file but are not unreferenced
361 * yet. (i915 and omapdrm have debugfs files which will show
362 * this.)
363 */
364 drm_mode_object_put(dev, &fb->base);
365 list_del(&fb->head);
366 dev->mode_config.num_fb--;
367}
368EXPORT_SYMBOL(drm_framebuffer_cleanup);
369
370/**
371 * drm_framebuffer_remove - remove and unreference a framebuffer object
372 * @fb: framebuffer to remove
373 *
374 * LOCKING:
375 * Caller must hold mode config lock.
376 *
377 * Scans all the CRTCs and planes in @dev's mode_config. If they're
378 * using @fb, removes it, setting it to NULL.
379 */
380void drm_framebuffer_remove(struct drm_framebuffer *fb)
381{
382 struct drm_device *dev = fb->dev;
323 struct drm_crtc *crtc; 383 struct drm_crtc *crtc;
324 struct drm_plane *plane; 384 struct drm_plane *plane;
325 struct drm_mode_set set; 385 struct drm_mode_set set;
@@ -350,11 +410,11 @@ void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
350 } 410 }
351 } 411 }
352 412
353 drm_mode_object_put(dev, &fb->base); 413 list_del(&fb->filp_head);
354 list_del(&fb->head); 414
355 dev->mode_config.num_fb--; 415 drm_framebuffer_unreference(fb);
356} 416}
357EXPORT_SYMBOL(drm_framebuffer_cleanup); 417EXPORT_SYMBOL(drm_framebuffer_remove);
358 418
359/** 419/**
360 * drm_crtc_init - Initialise a new CRTC object 420 * drm_crtc_init - Initialise a new CRTC object
@@ -1031,7 +1091,7 @@ void drm_mode_config_cleanup(struct drm_device *dev)
1031 } 1091 }
1032 1092
1033 list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { 1093 list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
1034 fb->funcs->destroy(fb); 1094 drm_framebuffer_remove(fb);
1035 } 1095 }
1036 1096
1037 list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, 1097 list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list,
@@ -2337,11 +2397,7 @@ int drm_mode_rmfb(struct drm_device *dev,
2337 goto out; 2397 goto out;
2338 } 2398 }
2339 2399
2340 /* TODO release all crtc connected to the framebuffer */ 2400 drm_framebuffer_remove(fb);
2341 /* TODO unhock the destructor from the buffer object */
2342
2343 list_del(&fb->filp_head);
2344 fb->funcs->destroy(fb);
2345 2401
2346out: 2402out:
2347 mutex_unlock(&dev->mode_config.mutex); 2403 mutex_unlock(&dev->mode_config.mutex);
@@ -2491,8 +2547,7 @@ void drm_fb_release(struct drm_file *priv)
2491 2547
2492 mutex_lock(&dev->mode_config.mutex); 2548 mutex_lock(&dev->mode_config.mutex);
2493 list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { 2549 list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
2494 list_del(&fb->filp_head); 2550 drm_framebuffer_remove(fb);
2495 fb->funcs->destroy(fb);
2496 } 2551 }
2497 mutex_unlock(&dev->mode_config.mutex); 2552 mutex_unlock(&dev->mode_config.mutex);
2498} 2553}