aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2012-12-10 14:42:17 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-01-20 16:17:00 -0500
commit362063619cf67c2c2fc2eb90951b2623cbb69a7c (patch)
tree58af436089e986b742d4ec91e5ea57e4a4b2aeb5 /drivers/gpu
parent786b99ed13223d8ac58a937dd348aead45eb8191 (diff)
drm: revamp framebuffer cleanup interfaces
We have two classes of framebuffer - Created by the driver (atm only for fbdev), and the driver holds onto the last reference count until destruction. - Created by userspace and associated with a given fd. These framebuffers will be reaped when their assoiciated fb is closed. Now these two cases are set up differently, the framebuffers are on different lists and hence destruction needs to clean up different things. Also, for userspace framebuffers we remove them from any current usage, whereas for internal framebuffers it is assumed that the driver has done this already. Long story short, we need two different ways to cleanup such drivers. Three functions are involved in total: - drm_framebuffer_remove: Convenience function which removes the fb from all active usage and then drops the passed-in reference. - drm_framebuffer_unregister_private: Will remove driver-private framebuffers from relevant lists and drop the corresponding references. Should be called for driver-private framebuffers before dropping the last reference (or like for a lot of the drivers where the fbdev is embedded someplace else, before doing the cleanup manually). - drm_framebuffer_cleanup: Final cleanup for both classes of fbs, should be called by the driver's ->destroy callback once the last reference is gone. This patch just rolls out the new interfaces and updates all drivers (by adding calls to drm_framebuffer_unregister_private at all the right places)- no functional changes yet. Follow-on patches will move drm core code around and update the lifetime management for framebuffers, so that we are no longer required to keep framebuffers alive by locking mode_config.mutex. I've also updated the kerneldoc already. vmwgfx seems to again be a bit special, at least I haven't figured out how the fbdev support in that driver works. It smells like it's external though. v2: The i915 driver creates another private framebuffer in the load-detect code. Adjust its cleanup code, too. Reviewed-by: Rob Clark <rob@ti.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/ast/ast_fb.c1
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_fbdev.c1
-rw-r--r--drivers/gpu/drm/drm_crtc.c31
-rw-r--r--drivers/gpu/drm/drm_fb_cma_helper.c5
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.c4
-rw-r--r--drivers/gpu/drm/gma500/framebuffer.c1
-rw-r--r--drivers/gpu/drm/i915/intel_display.c6
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c1
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_fb.c1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c1
-rw-r--r--drivers/gpu/drm/radeon/radeon_fb.c2
-rw-r--r--drivers/gpu/drm/udl/udl_fb.c1
12 files changed, 48 insertions, 7 deletions
diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c
index d9ec77959dff..3e6584b940dc 100644
--- a/drivers/gpu/drm/ast/ast_fb.c
+++ b/drivers/gpu/drm/ast/ast_fb.c
@@ -290,6 +290,7 @@ static void ast_fbdev_destroy(struct drm_device *dev,
290 drm_fb_helper_fini(&afbdev->helper); 290 drm_fb_helper_fini(&afbdev->helper);
291 291
292 vfree(afbdev->sysram); 292 vfree(afbdev->sysram);
293 drm_framebuffer_unregister_private(&afb->base);
293 drm_framebuffer_cleanup(&afb->base); 294 drm_framebuffer_cleanup(&afb->base);
294} 295}
295 296
diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
index 6c6b4c87d309..3daea0f638c3 100644
--- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c
+++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
@@ -258,6 +258,7 @@ static int cirrus_fbdev_destroy(struct drm_device *dev,
258 258
259 vfree(gfbdev->sysram); 259 vfree(gfbdev->sysram);
260 drm_fb_helper_fini(&gfbdev->helper); 260 drm_fb_helper_fini(&gfbdev->helper);
261 drm_framebuffer_unregister_private(&gfb->base);
261 drm_framebuffer_cleanup(&gfb->base); 262 drm_framebuffer_cleanup(&gfb->base);
262 263
263 return 0; 264 return 0;
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index f2ccda85309f..3eddfabeba96 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -68,6 +68,7 @@ void drm_modeset_unlock_all(struct drm_device *dev)
68 68
69 mutex_unlock(&dev->mode_config.mutex); 69 mutex_unlock(&dev->mode_config.mutex);
70} 70}
71
71EXPORT_SYMBOL(drm_modeset_unlock_all); 72EXPORT_SYMBOL(drm_modeset_unlock_all);
72 73
73/* Avoid boilerplate. I'm tired of typing. */ 74/* Avoid boilerplate. I'm tired of typing. */
@@ -430,11 +431,34 @@ void drm_framebuffer_reference(struct drm_framebuffer *fb)
430EXPORT_SYMBOL(drm_framebuffer_reference); 431EXPORT_SYMBOL(drm_framebuffer_reference);
431 432
432/** 433/**
434 * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr
435 * @fb: fb to unregister
436 *
437 * Drivers need to call this when cleaning up driver-private framebuffers, e.g.
438 * those used for fbdev. Note that the caller must hold a reference of it's own,
439 * i.e. the object may not be destroyed through this call (since it'll lead to a
440 * locking inversion).
441 */
442void drm_framebuffer_unregister_private(struct drm_framebuffer *fb)
443{
444}
445EXPORT_SYMBOL(drm_framebuffer_unregister_private);
446
447/**
433 * drm_framebuffer_cleanup - remove a framebuffer object 448 * drm_framebuffer_cleanup - remove a framebuffer object
434 * @fb: framebuffer to remove 449 * @fb: framebuffer to remove
435 * 450 *
436 * Scans all the CRTCs in @dev's mode_config. If they're using @fb, removes 451 * Cleanup references to a user-created framebuffer. This function is intended
437 * it, setting it to NULL. 452 * to be used from the drivers ->destroy callback.
453 *
454 * Note that this function does not remove the fb from active usuage - if it is
455 * still used anywhere, hilarity can ensue since userspace could call getfb on
456 * the id and get back -EINVAL. Obviously no concern at driver unload time.
457 *
458 * Also, the framebuffer will not be removed from the lookup idr - for
459 * user-created framebuffers this will happen in in the rmfb ioctl. For
460 * driver-private objects (e.g. for fbdev) drivers need to explicitly call
461 * drm_framebuffer_unregister_private.
438 */ 462 */
439void drm_framebuffer_cleanup(struct drm_framebuffer *fb) 463void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
440{ 464{
@@ -460,7 +484,8 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup);
460 * @fb: framebuffer to remove 484 * @fb: framebuffer to remove
461 * 485 *
462 * Scans all the CRTCs and planes in @dev's mode_config. If they're 486 * Scans all the CRTCs and planes in @dev's mode_config. If they're
463 * using @fb, removes it, setting it to NULL. 487 * using @fb, removes it, setting it to NULL. Then drops the reference to the
488 * passed-in framebuffer.
464 */ 489 */
465void drm_framebuffer_remove(struct drm_framebuffer *fb) 490void drm_framebuffer_remove(struct drm_framebuffer *fb)
466{ 491{
diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c
index e1e0cb0d531a..3742bc96421e 100644
--- a/drivers/gpu/drm/drm_fb_cma_helper.c
+++ b/drivers/gpu/drm/drm_fb_cma_helper.c
@@ -266,6 +266,7 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper,
266 return 0; 266 return 0;
267 267
268err_drm_fb_cma_destroy: 268err_drm_fb_cma_destroy:
269 drm_framebuffer_unregister_private(fb);
269 drm_fb_cma_destroy(fb); 270 drm_fb_cma_destroy(fb);
270err_framebuffer_release: 271err_framebuffer_release:
271 framebuffer_release(fbi); 272 framebuffer_release(fbi);
@@ -370,8 +371,10 @@ void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma)
370 framebuffer_release(info); 371 framebuffer_release(info);
371 } 372 }
372 373
373 if (fbdev_cma->fb) 374 if (fbdev_cma->fb) {
375 drm_framebuffer_unregister_private(&fbdev_cma->fb->fb);
374 drm_fb_cma_destroy(&fbdev_cma->fb->fb); 376 drm_fb_cma_destroy(&fbdev_cma->fb->fb);
377 }
375 378
376 drm_fb_helper_fini(&fbdev_cma->fb_helper); 379 drm_fb_helper_fini(&fbdev_cma->fb_helper);
377 kfree(fbdev_cma); 380 kfree(fbdev_cma);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index 71f867340a88..90d335cfb8c0 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -326,8 +326,10 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev,
326 /* release drm framebuffer and real buffer */ 326 /* release drm framebuffer and real buffer */
327 if (fb_helper->fb && fb_helper->fb->funcs) { 327 if (fb_helper->fb && fb_helper->fb->funcs) {
328 fb = fb_helper->fb; 328 fb = fb_helper->fb;
329 if (fb) 329 if (fb) {
330 drm_framebuffer_unregister_private(fb);
330 drm_framebuffer_remove(fb); 331 drm_framebuffer_remove(fb);
332 }
331 } 333 }
332 334
333 /* release linux framebuffer */ 335 /* release linux framebuffer */
diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c
index 49800d2b79dd..c1ef37e2efdf 100644
--- a/drivers/gpu/drm/gma500/framebuffer.c
+++ b/drivers/gpu/drm/gma500/framebuffer.c
@@ -590,6 +590,7 @@ static int psb_fbdev_destroy(struct drm_device *dev, struct psb_fbdev *fbdev)
590 framebuffer_release(info); 590 framebuffer_release(info);
591 } 591 }
592 drm_fb_helper_fini(&fbdev->psb_fb_helper); 592 drm_fb_helper_fini(&fbdev->psb_fb_helper);
593 drm_framebuffer_unregister_private(&psbfb->base);
593 drm_framebuffer_cleanup(&psbfb->base); 594 drm_framebuffer_cleanup(&psbfb->base);
594 595
595 if (psbfb->gtt) 596 if (psbfb->gtt)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 26fa6a795afe..df51203dcebd 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -6789,8 +6789,10 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
6789 intel_encoder->new_crtc = NULL; 6789 intel_encoder->new_crtc = NULL;
6790 intel_set_mode(crtc, NULL, 0, 0, NULL); 6790 intel_set_mode(crtc, NULL, 0, 0, NULL);
6791 6791
6792 if (old->release_fb) 6792 if (old->release_fb) {
6793 old->release_fb->funcs->destroy(old->release_fb); 6793 drm_framebuffer_unregister_private(old->release_fb);
6794 drm_framebuffer_unreference(old->release_fb);
6795 }
6794 6796
6795 return; 6797 return;
6796 } 6798 }
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index a9f7280f87fb..c7b8316137e9 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -212,6 +212,7 @@ static void intel_fbdev_destroy(struct drm_device *dev,
212 212
213 drm_fb_helper_fini(&ifbdev->helper); 213 drm_fb_helper_fini(&ifbdev->helper);
214 214
215 drm_framebuffer_unregister_private(&ifb->base);
215 drm_framebuffer_cleanup(&ifb->base); 216 drm_framebuffer_cleanup(&ifb->base);
216 if (ifb->obj) { 217 if (ifb->obj) {
217 drm_gem_object_unreference_unlocked(&ifb->obj->base); 218 drm_gem_object_unreference_unlocked(&ifb->obj->base);
diff --git a/drivers/gpu/drm/mgag200/mgag200_fb.c b/drivers/gpu/drm/mgag200/mgag200_fb.c
index 2f486481d79a..5c69b432f99a 100644
--- a/drivers/gpu/drm/mgag200/mgag200_fb.c
+++ b/drivers/gpu/drm/mgag200/mgag200_fb.c
@@ -247,6 +247,7 @@ static int mga_fbdev_destroy(struct drm_device *dev,
247 } 247 }
248 drm_fb_helper_fini(&mfbdev->helper); 248 drm_fb_helper_fini(&mfbdev->helper);
249 vfree(mfbdev->sysram); 249 vfree(mfbdev->sysram);
250 drm_framebuffer_unregister_private(&mfb->base);
250 drm_framebuffer_cleanup(&mfb->base); 251 drm_framebuffer_cleanup(&mfb->base);
251 252
252 return 0; 253 return 0;
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 67a1a069de28..d4ecb4deb484 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -433,6 +433,7 @@ nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon)
433 nouveau_fb->nvbo = NULL; 433 nouveau_fb->nvbo = NULL;
434 } 434 }
435 drm_fb_helper_fini(&fbcon->helper); 435 drm_fb_helper_fini(&fbcon->helper);
436 drm_framebuffer_unregister_private(&nouveau_fb->base);
436 drm_framebuffer_cleanup(&nouveau_fb->base); 437 drm_framebuffer_cleanup(&nouveau_fb->base);
437 return 0; 438 return 0;
438} 439}
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index cc8489d8c6d1..515e5ee1f9ee 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -293,6 +293,7 @@ out_unref:
293 } 293 }
294 if (fb && ret) { 294 if (fb && ret) {
295 drm_gem_object_unreference(gobj); 295 drm_gem_object_unreference(gobj);
296 drm_framebuffer_unregister_private(fb);
296 drm_framebuffer_cleanup(fb); 297 drm_framebuffer_cleanup(fb);
297 kfree(fb); 298 kfree(fb);
298 } 299 }
@@ -339,6 +340,7 @@ static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfb
339 rfb->obj = NULL; 340 rfb->obj = NULL;
340 } 341 }
341 drm_fb_helper_fini(&rfbdev->helper); 342 drm_fb_helper_fini(&rfbdev->helper);
343 drm_framebuffer_unregister_private(&rfb->base);
342 drm_framebuffer_cleanup(&rfb->base); 344 drm_framebuffer_cleanup(&rfb->base);
343 345
344 return 0; 346 return 0;
diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c
index f8904b4e68de..caa84f1de9c1 100644
--- a/drivers/gpu/drm/udl/udl_fb.c
+++ b/drivers/gpu/drm/udl/udl_fb.c
@@ -555,6 +555,7 @@ static void udl_fbdev_destroy(struct drm_device *dev,
555 framebuffer_release(info); 555 framebuffer_release(info);
556 } 556 }
557 drm_fb_helper_fini(&ufbdev->helper); 557 drm_fb_helper_fini(&ufbdev->helper);
558 drm_framebuffer_unregister_private(&ufbdev->ufb.base);
558 drm_framebuffer_cleanup(&ufbdev->ufb.base); 559 drm_framebuffer_cleanup(&ufbdev->ufb.base);
559 drm_gem_object_unreference_unlocked(&ufbdev->ufb.obj->base); 560 drm_gem_object_unreference_unlocked(&ufbdev->ufb.obj->base);
560} 561}