diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2014-04-23 04:24:11 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2014-04-23 14:07:00 -0400 |
commit | 731cce487ab0485c6607e44a0759d92bef1c144e (patch) | |
tree | edf6a9e353508a976e13d35df175f307f50ed014 | |
parent | 0fe27f063fcef920a0be93ad5e89d9c8ef5c5858 (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.c | 14 |
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 | } |