aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2014-04-23 04:24:11 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2014-04-23 14:07:00 -0400
commit731cce487ab0485c6607e44a0759d92bef1c144e (patch)
treeedf6a9e353508a976e13d35df175f307f50ed014
parent0fe27f063fcef920a0be93ad5e89d9c8ef5c5858 (diff)
drm: Handle ->disable_plane failures correctly
The ->disable_plane hook always had a return value, but only since the introduction of primary planes was there any implementation that actually failed. So handle such failures correctly. Note that drm_plane_force_disable is special: In the modeset cleanup case we first disable all crtc, so primary planes should all be freed already. And in the fb helper we only reset non-primary planes. Still better be paranoid and add an early return. I don't see how this could happen, but it might fix the fb refcount underrun Thierry is seeing. Matt Roper spotted this issue. Cc: Thierry Reding <treding@nvidia.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Matt Roper <matthew.d.roper@intel.com> Reviewed-by: Matt Roper <matthew.d.roper@intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r--drivers/gpu/drm/drm_crtc.c14
1 files changed, 10 insertions, 4 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index f6633cb927bc..461d19bd14ee 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1152,8 +1152,10 @@ void drm_plane_force_disable(struct drm_plane *plane)
1152 return; 1152 return;
1153 1153
1154 ret = plane->funcs->disable_plane(plane); 1154 ret = plane->funcs->disable_plane(plane);
1155 if (ret) 1155 if (ret) {
1156 DRM_ERROR("failed to disable plane with busy fb\n"); 1156 DRM_ERROR("failed to disable plane with busy fb\n");
1157 return;
1158 }
1157 /* disconnect the plane from the fb and crtc: */ 1159 /* disconnect the plane from the fb and crtc: */
1158 __drm_framebuffer_unreference(old_fb); 1160 __drm_framebuffer_unreference(old_fb);
1159 plane->fb = NULL; 1161 plane->fb = NULL;
@@ -2117,9 +2119,13 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
2117 if (!plane_req->fb_id) { 2119 if (!plane_req->fb_id) {
2118 drm_modeset_lock_all(dev); 2120 drm_modeset_lock_all(dev);
2119 old_fb = plane->fb; 2121 old_fb = plane->fb;
2120 plane->funcs->disable_plane(plane); 2122 ret = plane->funcs->disable_plane(plane);
2121 plane->crtc = NULL; 2123 if (!ret) {
2122 plane->fb = NULL; 2124 plane->crtc = NULL;
2125 plane->fb = NULL;
2126 } else {
2127 old_fb = NULL;
2128 }
2123 drm_modeset_unlock_all(dev); 2129 drm_modeset_unlock_all(dev);
2124 goto out; 2130 goto out;
2125 } 2131 }