aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_crtc.c
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2012-12-10 19:07:12 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-01-20 16:17:09 -0500
commitb0d1232589df5575c5971224ac4cb30e7e525884 (patch)
tree21336a0066a019ad4f5bff093a8f824c50540d83 /drivers/gpu/drm/drm_crtc.c
parent6c2a75325c800de286166c693e0cd33c3a1c5ec8 (diff)
drm: refcounting for crtc framebuffers
With the prep patch to encapsulate ->set_crtc calls, this is now rather easy. Hooray for inconsistent semantics between ->set_crtc and ->page_flip, where the driver callback is supposed to update the fb pointer, and ->update_plane, where the drm core does the same. Also, since the drm core functions check crtc->fb before calling into driver callbacks, we can't really reduce the critical sections protected by the mode_config locks. Reviewed-by: Rob Clark <rob@ti.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/drm_crtc.c')
-rw-r--r--drivers/gpu/drm/drm_crtc.c37
1 files changed, 30 insertions, 7 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 64ef12079528..6dc75ee10079 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1984,8 +1984,21 @@ out:
1984int drm_mode_set_config_internal(struct drm_mode_set *set) 1984int drm_mode_set_config_internal(struct drm_mode_set *set)
1985{ 1985{
1986 struct drm_crtc *crtc = set->crtc; 1986 struct drm_crtc *crtc = set->crtc;
1987 struct drm_framebuffer *fb, *old_fb;
1988 int ret;
1989
1990 old_fb = crtc->fb;
1991 fb = set->fb;
1987 1992
1988 return crtc->funcs->set_config(set); 1993 ret = crtc->funcs->set_config(set);
1994 if (ret == 0) {
1995 if (old_fb)
1996 drm_framebuffer_unreference(old_fb);
1997 if (fb)
1998 drm_framebuffer_reference(fb);
1999 }
2000
2001 return ret;
1989} 2002}
1990EXPORT_SYMBOL(drm_mode_set_config_internal); 2003EXPORT_SYMBOL(drm_mode_set_config_internal);
1991 2004
@@ -2046,6 +2059,8 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
2046 goto out; 2059 goto out;
2047 } 2060 }
2048 fb = crtc->fb; 2061 fb = crtc->fb;
2062 /* Make refcounting symmetric with the lookup path. */
2063 drm_framebuffer_reference(fb);
2049 } else { 2064 } else {
2050 fb = drm_framebuffer_lookup(dev, crtc_req->fb_id); 2065 fb = drm_framebuffer_lookup(dev, crtc_req->fb_id);
2051 if (!fb) { 2066 if (!fb) {
@@ -2054,9 +2069,6 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
2054 ret = -EINVAL; 2069 ret = -EINVAL;
2055 goto out; 2070 goto out;
2056 } 2071 }
2057 /* fb is protect by the mode_config lock, so drop the
2058 * ref immediately */
2059 drm_framebuffer_unreference(fb);
2060 } 2072 }
2061 2073
2062 mode = drm_mode_create(dev); 2074 mode = drm_mode_create(dev);
@@ -2156,6 +2168,9 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
2156 ret = drm_mode_set_config_internal(&set); 2168 ret = drm_mode_set_config_internal(&set);
2157 2169
2158out: 2170out:
2171 if (fb)
2172 drm_framebuffer_unreference(fb);
2173
2159 kfree(connector_set); 2174 kfree(connector_set);
2160 drm_mode_destroy(dev, mode); 2175 drm_mode_destroy(dev, mode);
2161 drm_modeset_unlock_all(dev); 2176 drm_modeset_unlock_all(dev);
@@ -3656,7 +3671,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
3656 struct drm_mode_crtc_page_flip *page_flip = data; 3671 struct drm_mode_crtc_page_flip *page_flip = data;
3657 struct drm_mode_object *obj; 3672 struct drm_mode_object *obj;
3658 struct drm_crtc *crtc; 3673 struct drm_crtc *crtc;
3659 struct drm_framebuffer *fb; 3674 struct drm_framebuffer *fb = NULL, *old_fb = NULL;
3660 struct drm_pending_vblank_event *e = NULL; 3675 struct drm_pending_vblank_event *e = NULL;
3661 unsigned long flags; 3676 unsigned long flags;
3662 int hdisplay, vdisplay; 3677 int hdisplay, vdisplay;
@@ -3687,8 +3702,6 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
3687 fb = drm_framebuffer_lookup(dev, page_flip->fb_id); 3702 fb = drm_framebuffer_lookup(dev, page_flip->fb_id);
3688 if (!fb) 3703 if (!fb)
3689 goto out; 3704 goto out;
3690 /* fb is protect by the mode_config lock, so drop the ref immediately */
3691 drm_framebuffer_unreference(fb);
3692 3705
3693 hdisplay = crtc->mode.hdisplay; 3706 hdisplay = crtc->mode.hdisplay;
3694 vdisplay = crtc->mode.vdisplay; 3707 vdisplay = crtc->mode.vdisplay;
@@ -3734,6 +3747,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
3734 (void (*) (struct drm_pending_event *)) kfree; 3747 (void (*) (struct drm_pending_event *)) kfree;
3735 } 3748 }
3736 3749
3750 old_fb = crtc->fb;
3737 ret = crtc->funcs->page_flip(crtc, fb, e); 3751 ret = crtc->funcs->page_flip(crtc, fb, e);
3738 if (ret) { 3752 if (ret) {
3739 if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { 3753 if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
@@ -3742,9 +3756,18 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
3742 spin_unlock_irqrestore(&dev->event_lock, flags); 3756 spin_unlock_irqrestore(&dev->event_lock, flags);
3743 kfree(e); 3757 kfree(e);
3744 } 3758 }
3759 /* Keep the old fb, don't unref it. */
3760 old_fb = NULL;
3761 } else {
3762 /* Unref only the old framebuffer. */
3763 fb = NULL;
3745 } 3764 }
3746 3765
3747out: 3766out:
3767 if (fb)
3768 drm_framebuffer_unreference(fb);
3769 if (old_fb)
3770 drm_framebuffer_unreference(old_fb);
3748 drm_modeset_unlock_all(dev); 3771 drm_modeset_unlock_all(dev);
3749 return ret; 3772 return ret;
3750} 3773}