drm/atomic: track bitmask of planes attached to crtc

Chasing plane->state->crtc of planes that are *not* part of the same
atomic update is racy, making it incredibly awkward (or impossible) to
do something simple like iterate over all planes and figure out which
ones are attached to a crtc.

Solve this by adding a bitmask of currently attached planes in the
crtc-state.

Note that the transitional helpers do not maintain the plane_mask.  But
they only support the legacy ioctls, which have sufficient brute-force
locking around plane updates that they can continue to loop over all
planes to see what is attached to a crtc the old way.

Signed-off-by: Rob Clark <robdclark@gmail.com>
[danvet:
- Drop comments about locking in set_crtc_for_plane since they're a
  bit misleading - we already should hold lock for the current crtc.
- Also WARN_ON if get_state on the old crtc fails since that should
  have been done already.
- Squash in fixup to check get_plane_state return value, reported by
  Dan Carpenter and acked by Rob Clark.]
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index ba49b5c..ff5f034 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -344,7 +344,8 @@
 
 /**
  * drm_atomic_set_crtc_for_plane - set crtc for plane
- * @plane_state: atomic state object for the plane
+ * @state: the incoming atomic state
+ * @plane: the plane whose incoming state to update
  * @crtc: crtc to use for the plane
  *
  * Changing the assigned crtc for a plane requires us to grab the lock and state
@@ -357,20 +358,35 @@
  * sequence must be restarted. All other errors are fatal.
  */
 int
-drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
-			      struct drm_crtc *crtc)
+drm_atomic_set_crtc_for_plane(struct drm_atomic_state *state,
+			      struct drm_plane *plane, struct drm_crtc *crtc)
 {
+	struct drm_plane_state *plane_state =
+			drm_atomic_get_plane_state(state, plane);
 	struct drm_crtc_state *crtc_state;
 
+	if (WARN_ON(IS_ERR(plane_state)))
+		return PTR_ERR(plane_state);
+
+	if (plane_state->crtc) {
+		crtc_state = drm_atomic_get_crtc_state(plane_state->state,
+						       plane_state->crtc);
+		if (WARN_ON(IS_ERR(crtc_state)))
+			return PTR_ERR(crtc_state);
+
+		crtc_state->plane_mask &= ~(1 << drm_plane_index(plane));
+	}
+
+	plane_state->crtc = crtc;
+
 	if (crtc) {
 		crtc_state = drm_atomic_get_crtc_state(plane_state->state,
 						       crtc);
 		if (IS_ERR(crtc_state))
 			return PTR_ERR(crtc_state);
+		crtc_state->plane_mask |= (1 << drm_plane_index(plane));
 	}
 
-	plane_state->crtc = crtc;
-
 	if (crtc)
 		DRM_DEBUG_KMS("Link plane state %p to [CRTC:%d]\n",
 			      plane_state, crtc->base.id);