Selaa lähdekoodia

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>
Daniel Vetter 11 vuotta sitten
vanhempi
commit
731cce487a
1 muutettua tiedostoa jossa 10 lisäystä ja 4 poistoa
  1. 10 4
      drivers/gpu/drm/drm_crtc.c

+ 10 - 4
drivers/gpu/drm/drm_crtc.c

@@ -1152,8 +1152,10 @@ void drm_plane_force_disable(struct drm_plane *plane)
 		return;
 
 	ret = plane->funcs->disable_plane(plane);
-	if (ret)
+	if (ret) {
 		DRM_ERROR("failed to disable plane with busy fb\n");
+		return;
+	}
 	/* disconnect the plane from the fb and crtc: */
 	__drm_framebuffer_unreference(old_fb);
 	plane->fb = NULL;
@@ -2117,9 +2119,13 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
 	if (!plane_req->fb_id) {
 		drm_modeset_lock_all(dev);
 		old_fb = plane->fb;
-		plane->funcs->disable_plane(plane);
-		plane->crtc = NULL;
-		plane->fb = NULL;
+		ret = plane->funcs->disable_plane(plane);
+		if (!ret) {
+			plane->crtc = NULL;
+			plane->fb = NULL;
+		} else {
+			old_fb = NULL;
+		}
 		drm_modeset_unlock_all(dev);
 		goto out;
 	}