Skip to content

Commit

Permalink
drm: revamp framebuffer cleanup interfaces
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
danvet committed Jan 20, 2013
1 parent 786b99e commit 3620636
Show file tree
Hide file tree
Showing 14 changed files with 55 additions and 9 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/drm/ast/ast_fb.c
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ static void ast_fbdev_destroy(struct drm_device *dev,
drm_fb_helper_fini(&afbdev->helper);

vfree(afbdev->sysram);
drm_framebuffer_unregister_private(&afb->base);
drm_framebuffer_cleanup(&afb->base);
}

Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/cirrus/cirrus_fbdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ static int cirrus_fbdev_destroy(struct drm_device *dev,

vfree(gfbdev->sysram);
drm_fb_helper_fini(&gfbdev->helper);
drm_framebuffer_unregister_private(&gfb->base);
drm_framebuffer_cleanup(&gfb->base);

return 0;
Expand Down
31 changes: 28 additions & 3 deletions drivers/gpu/drm/drm_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ void drm_modeset_unlock_all(struct drm_device *dev)

mutex_unlock(&dev->mode_config.mutex);
}

EXPORT_SYMBOL(drm_modeset_unlock_all);

/* Avoid boilerplate. I'm tired of typing. */
Expand Down Expand Up @@ -429,12 +430,35 @@ void drm_framebuffer_reference(struct drm_framebuffer *fb)
}
EXPORT_SYMBOL(drm_framebuffer_reference);

/**
* drm_framebuffer_unregister_private - unregister a private fb from the lookup idr
* @fb: fb to unregister
*
* Drivers need to call this when cleaning up driver-private framebuffers, e.g.
* those used for fbdev. Note that the caller must hold a reference of it's own,
* i.e. the object may not be destroyed through this call (since it'll lead to a
* locking inversion).
*/
void drm_framebuffer_unregister_private(struct drm_framebuffer *fb)
{
}
EXPORT_SYMBOL(drm_framebuffer_unregister_private);

/**
* drm_framebuffer_cleanup - remove a framebuffer object
* @fb: framebuffer to remove
*
* Scans all the CRTCs in @dev's mode_config. If they're using @fb, removes
* it, setting it to NULL.
* Cleanup references to a user-created framebuffer. This function is intended
* to be used from the drivers ->destroy callback.
*
* Note that this function does not remove the fb from active usuage - if it is
* still used anywhere, hilarity can ensue since userspace could call getfb on
* the id and get back -EINVAL. Obviously no concern at driver unload time.
*
* Also, the framebuffer will not be removed from the lookup idr - for
* user-created framebuffers this will happen in in the rmfb ioctl. For
* driver-private objects (e.g. for fbdev) drivers need to explicitly call
* drm_framebuffer_unregister_private.
*/
void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
{
Expand All @@ -460,7 +484,8 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup);
* @fb: framebuffer to remove
*
* Scans all the CRTCs and planes in @dev's mode_config. If they're
* using @fb, removes it, setting it to NULL.
* using @fb, removes it, setting it to NULL. Then drops the reference to the
* passed-in framebuffer.
*/
void drm_framebuffer_remove(struct drm_framebuffer *fb)
{
Expand Down
5 changes: 4 additions & 1 deletion drivers/gpu/drm/drm_fb_cma_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper,
return 0;

err_drm_fb_cma_destroy:
drm_framebuffer_unregister_private(fb);
drm_fb_cma_destroy(fb);
err_framebuffer_release:
framebuffer_release(fbi);
Expand Down Expand Up @@ -370,8 +371,10 @@ void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma)
framebuffer_release(info);
}

if (fbdev_cma->fb)
if (fbdev_cma->fb) {
drm_framebuffer_unregister_private(&fbdev_cma->fb->fb);
drm_fb_cma_destroy(&fbdev_cma->fb->fb);
}

drm_fb_helper_fini(&fbdev_cma->fb_helper);
kfree(fbdev_cma);
Expand Down
4 changes: 3 additions & 1 deletion drivers/gpu/drm/exynos/exynos_drm_fbdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -326,8 +326,10 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev,
/* release drm framebuffer and real buffer */
if (fb_helper->fb && fb_helper->fb->funcs) {
fb = fb_helper->fb;
if (fb)
if (fb) {
drm_framebuffer_unregister_private(fb);
drm_framebuffer_remove(fb);
}
}

/* release linux framebuffer */
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/gma500/framebuffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,7 @@ static int psb_fbdev_destroy(struct drm_device *dev, struct psb_fbdev *fbdev)
framebuffer_release(info);
}
drm_fb_helper_fini(&fbdev->psb_fb_helper);
drm_framebuffer_unregister_private(&psbfb->base);
drm_framebuffer_cleanup(&psbfb->base);

if (psbfb->gtt)
Expand Down
6 changes: 4 additions & 2 deletions drivers/gpu/drm/i915/intel_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -6789,8 +6789,10 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
intel_encoder->new_crtc = NULL;
intel_set_mode(crtc, NULL, 0, 0, NULL);

if (old->release_fb)
old->release_fb->funcs->destroy(old->release_fb);
if (old->release_fb) {
drm_framebuffer_unregister_private(old->release_fb);
drm_framebuffer_unreference(old->release_fb);
}

return;
}
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/intel_fb.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ static void intel_fbdev_destroy(struct drm_device *dev,

drm_fb_helper_fini(&ifbdev->helper);

drm_framebuffer_unregister_private(&ifb->base);
drm_framebuffer_cleanup(&ifb->base);
if (ifb->obj) {
drm_gem_object_unreference_unlocked(&ifb->obj->base);
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/mgag200/mgag200_fb.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ static int mga_fbdev_destroy(struct drm_device *dev,
}
drm_fb_helper_fini(&mfbdev->helper);
vfree(mfbdev->sysram);
drm_framebuffer_unregister_private(&mfb->base);
drm_framebuffer_cleanup(&mfb->base);

return 0;
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/nouveau/nouveau_fbcon.c
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,7 @@ nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon)
nouveau_fb->nvbo = NULL;
}
drm_fb_helper_fini(&fbcon->helper);
drm_framebuffer_unregister_private(&nouveau_fb->base);
drm_framebuffer_cleanup(&nouveau_fb->base);
return 0;
}
Expand Down
2 changes: 2 additions & 0 deletions drivers/gpu/drm/radeon/radeon_fb.c
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ static int radeonfb_create(struct radeon_fbdev *rfbdev,
}
if (fb && ret) {
drm_gem_object_unreference(gobj);
drm_framebuffer_unregister_private(fb);
drm_framebuffer_cleanup(fb);
kfree(fb);
}
Expand Down Expand Up @@ -339,6 +340,7 @@ static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfb
rfb->obj = NULL;
}
drm_fb_helper_fini(&rfbdev->helper);
drm_framebuffer_unregister_private(&rfb->base);
drm_framebuffer_cleanup(&rfb->base);

return 0;
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/udl/udl_fb.c
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,7 @@ static void udl_fbdev_destroy(struct drm_device *dev,
framebuffer_release(info);
}
drm_fb_helper_fini(&ufbdev->helper);
drm_framebuffer_unregister_private(&ufbdev->ufb.base);
drm_framebuffer_cleanup(&ufbdev->ufb.base);
drm_gem_object_unreference_unlocked(&ufbdev->ufb.obj->base);
}
Expand Down
8 changes: 6 additions & 2 deletions drivers/staging/omapdrm/omap_fbdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,10 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
if (ret) {
if (fbi)
framebuffer_release(fbi);
if (fb)
if (fb) {
drm_framebuffer_unregister_private(fb);
drm_framebuffer_remove(fb);
}
}

return ret;
Expand Down Expand Up @@ -400,8 +402,10 @@ void omap_fbdev_free(struct drm_device *dev)
fbdev = to_omap_fbdev(priv->fbdev);

/* this will free the backing object */
if (fbdev->fb)
if (fbdev->fb) {
drm_framebuffer_unregister_private(fbdev->fb);
drm_framebuffer_remove(fbdev->fb);
}

kfree(fbdev);

Expand Down
1 change: 1 addition & 0 deletions include/drm/drm_crtc.h
Original file line number Diff line number Diff line change
Expand Up @@ -964,6 +964,7 @@ extern void drm_framebuffer_unreference(struct drm_framebuffer *fb);
extern void drm_framebuffer_reference(struct drm_framebuffer *fb);
extern void drm_framebuffer_remove(struct drm_framebuffer *fb);
extern void drm_framebuffer_cleanup(struct drm_framebuffer *fb);
extern void drm_framebuffer_unregister_private(struct drm_framebuffer *fb);
extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc);
extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
extern void drm_crtc_probe_connector_modes(struct drm_device *dev, int maxX, int maxY);
Expand Down

0 comments on commit 3620636

Please sign in to comment.