drm/atomic: Integrate fence support

This patch is for enabling async commits. It replaces an earlier
approach which added an async boolean paramter to the ->prepare_fb
callbacks. The idea is that prepare_fb picks up the right fence to
synchronize against, which is then used by the synchronous commit
helper. For async commits drivers can either register a callback to
the fence or simply do the synchronous wait in their async work queue.

v2: Remove unused variable.

v3: Only wait for fences after the point of no return in the part
of the commit function which can be run asynchronously. This is after
the atomic state has been swapped in, hence now check
plane->state->fence.

Also add a WARN_ON to make sure we don't try to wait on a fence when
there's no fb, just as a sanity check.

Reviewed-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 077c792..4808e71 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -30,6 +30,7 @@
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_atomic_helper.h>
+#include <linux/fence.h>
 
 static void
 drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
@@ -712,6 +713,26 @@
 }
 EXPORT_SYMBOL(drm_atomic_helper_commit_post_planes);
 
+static void wait_for_fences(struct drm_device *dev,
+			    struct drm_atomic_state *state)
+{
+	int nplanes = dev->mode_config.num_total_plane;
+	int i;
+
+	for (i = 0; i < nplanes; i++) {
+		struct drm_plane *plane = state->planes[i];
+
+		if (!plane || !plane->state->fence)
+			continue;
+
+		WARN_ON(!plane->state->fb);
+
+		fence_wait(plane->state->fence, false);
+		fence_put(plane->state->fence);
+		plane->state->fence = NULL;
+	}
+}
+
 static void
 wait_for_vblanks(struct drm_device *dev, struct drm_atomic_state *old_state)
 {
@@ -809,6 +830,8 @@
 	 * current layout.
 	 */
 
+	wait_for_fences(dev, state);
+
 	drm_atomic_helper_commit_pre_planes(dev, state);
 
 	drm_atomic_helper_commit_planes(dev, state);