drm/atomic-helpers: Invoke end_fb_access while owning plane state
[linux-2.6-microblaze.git] / drivers / gpu / drm / drm_atomic_helper.c
index 2444fc3..68ffcc0 100644 (file)
@@ -2012,7 +2012,7 @@ int drm_atomic_helper_commit(struct drm_device *dev,
                        return ret;
 
                drm_atomic_helper_async_commit(dev, state);
-               drm_atomic_helper_cleanup_planes(dev, state);
+               drm_atomic_helper_unprepare_planes(dev, state);
 
                return 0;
        }
@@ -2072,7 +2072,7 @@ int drm_atomic_helper_commit(struct drm_device *dev,
        return 0;
 
 err:
-       drm_atomic_helper_cleanup_planes(dev, state);
+       drm_atomic_helper_unprepare_planes(dev, state);
        return ret;
 }
 EXPORT_SYMBOL(drm_atomic_helper_commit);
@@ -2650,6 +2650,39 @@ fail_prepare_fb:
 }
 EXPORT_SYMBOL(drm_atomic_helper_prepare_planes);
 
+/**
+ * drm_atomic_helper_unprepare_planes - release plane resources on aborts
+ * @dev: DRM device
+ * @state: atomic state object with old state structures
+ *
+ * This function cleans up plane state, specifically framebuffers, from the
+ * atomic state. It undoes the effects of drm_atomic_helper_prepare_planes()
+ * when aborting an atomic commit. For cleaning up after a successful commit
+ * use drm_atomic_helper_cleanup_planes().
+ */
+void drm_atomic_helper_unprepare_planes(struct drm_device *dev,
+                                       struct drm_atomic_state *state)
+{
+       struct drm_plane *plane;
+       struct drm_plane_state *new_plane_state;
+       int i;
+
+       for_each_new_plane_in_state(state, plane, new_plane_state, i) {
+               const struct drm_plane_helper_funcs *funcs = plane->helper_private;
+
+               if (funcs->end_fb_access)
+                       funcs->end_fb_access(plane, new_plane_state);
+       }
+
+       for_each_new_plane_in_state(state, plane, new_plane_state, i) {
+               const struct drm_plane_helper_funcs *funcs = plane->helper_private;
+
+               if (funcs->cleanup_fb)
+                       funcs->cleanup_fb(plane, new_plane_state);
+       }
+}
+EXPORT_SYMBOL(drm_atomic_helper_unprepare_planes);
+
 static bool plane_crtc_active(const struct drm_plane_state *state)
 {
        return state->crtc && state->crtc->state->active;
@@ -2784,6 +2817,17 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
 
                funcs->atomic_flush(crtc, old_state);
        }
+
+       /*
+        * Signal end of framebuffer access here before hw_done. After hw_done,
+        * a later commit might have already released the plane state.
+        */
+       for_each_old_plane_in_state(old_state, plane, old_plane_state, i) {
+               const struct drm_plane_helper_funcs *funcs = plane->helper_private;
+
+               if (funcs->end_fb_access)
+                       funcs->end_fb_access(plane, old_plane_state);
+       }
 }
 EXPORT_SYMBOL(drm_atomic_helper_commit_planes);
 
@@ -2911,40 +2955,22 @@ EXPORT_SYMBOL(drm_atomic_helper_disable_planes_on_crtc);
  * configuration. Hence the old configuration must be perserved in @old_state to
  * be able to call this function.
  *
- * This function must also be called on the new state when the atomic update
- * fails at any point after calling drm_atomic_helper_prepare_planes().
+ * This function may not be called on the new state when the atomic update
+ * fails at any point after calling drm_atomic_helper_prepare_planes(). Use
+ * drm_atomic_helper_unprepare_planes() in this case.
  */
 void drm_atomic_helper_cleanup_planes(struct drm_device *dev,
                                      struct drm_atomic_state *old_state)
 {
        struct drm_plane *plane;
-       struct drm_plane_state *old_plane_state, *new_plane_state;
+       struct drm_plane_state *old_plane_state;
        int i;
 
-       for_each_oldnew_plane_in_state(old_state, plane, old_plane_state, new_plane_state, i) {
+       for_each_old_plane_in_state(old_state, plane, old_plane_state, i) {
                const struct drm_plane_helper_funcs *funcs = plane->helper_private;
 
-               if (funcs->end_fb_access)
-                       funcs->end_fb_access(plane, new_plane_state);
-       }
-
-       for_each_oldnew_plane_in_state(old_state, plane, old_plane_state, new_plane_state, i) {
-               const struct drm_plane_helper_funcs *funcs;
-               struct drm_plane_state *plane_state;
-
-               /*
-                * This might be called before swapping when commit is aborted,
-                * in which case we have to cleanup the new state.
-                */
-               if (old_plane_state == plane->state)
-                       plane_state = new_plane_state;
-               else
-                       plane_state = old_plane_state;
-
-               funcs = plane->helper_private;
-
                if (funcs->cleanup_fb)
-                       funcs->cleanup_fb(plane, plane_state);
+                       funcs->cleanup_fb(plane, old_plane_state);
        }
 }
 EXPORT_SYMBOL(drm_atomic_helper_cleanup_planes);