This allows iteration over encoders without requiring connection_mutex.

Changes since v1:
- Add a set_best_encoder helper function and update encoder_mask inside
  it.
Changes since v2:
- Relax the WARN_ON(!crtc), with explanation.
- Call set_best_encoder when connector is moved between crtc's.
- Add some paranoia to steal_encoder to prevent accidentally setting
  best_encoder to NULL.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
---
diff --git a/drivers/gpu/drm/drm_atomic_helper.c 
b/drivers/gpu/drm/drm_atomic_helper.c
index 9c84b3b37631..391b3783e341 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -125,6 +125,47 @@ get_current_crtc_for_encoder(struct drm_device *dev,
        return NULL;
 }

+static void
+set_best_encoder(struct drm_atomic_state *state,
+                struct drm_connector_state *conn_state,
+                struct drm_encoder *encoder)
+{
+       struct drm_crtc_state *crtc_state;
+       struct drm_crtc *crtc;
+
+       if (conn_state->best_encoder) {
+               /* Unset the encoder_mask in the old crtc state. */
+               crtc = conn_state->connector->state->crtc;
+
+               /* A NULL crtc is an error here because we should have
+                *  duplicated a NULL best_encoder when crtc was NULL.
+                * As an exception restoring duplicated atomic state
+                * during resume is allowed, so don't warn when
+                * best_encoder is equal to encoder we intend to set.
+                */
+               WARN_ON(!crtc && encoder != conn_state->best_encoder);
+               if (crtc) {
+                       crtc_state = drm_atomic_get_existing_crtc_state(state, 
crtc);
+
+                       crtc_state->encoder_mask &=
+                               ~(1 << 
drm_encoder_index(conn_state->best_encoder));
+               }
+       }
+
+       if (encoder) {
+               crtc = conn_state->crtc;
+               WARN_ON(!crtc);
+               if (crtc) {
+                       crtc_state = drm_atomic_get_existing_crtc_state(state, 
crtc);
+
+                       crtc_state->encoder_mask |=
+                               1 << drm_encoder_index(encoder);
+               }
+       }
+
+       conn_state->best_encoder = encoder;
+}
+
 static int
 steal_encoder(struct drm_atomic_state *state,
              struct drm_encoder *encoder,
@@ -164,7 +205,10 @@ steal_encoder(struct drm_atomic_state *state,
                if (IS_ERR(connector_state))
                        return PTR_ERR(connector_state);

-               connector_state->best_encoder = NULL;
+               if (connector_state->best_encoder != encoder)
+                       continue;
+
+               set_best_encoder(state, connector_state, NULL);
        }

        return 0;
@@ -212,7 +256,7 @@ update_connector_routing(struct drm_atomic_state *state, 
int conn_idx)
                                connector->base.id,
                                connector->name);

-               connector_state->best_encoder = NULL;
+               set_best_encoder(state, connector_state, NULL);

                return 0;
        }
@@ -241,6 +285,8 @@ update_connector_routing(struct drm_atomic_state *state, 
int conn_idx)
        }

        if (new_encoder == connector_state->best_encoder) {
+               set_best_encoder(state, connector_state, new_encoder);
+
                DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] keeps [ENCODER:%d:%s], now 
on [CRTC:%d:%s]\n",
                                 connector->base.id,
                                 connector->name,
@@ -275,7 +321,8 @@ update_connector_routing(struct drm_atomic_state *state, 
int conn_idx)
        if (WARN_ON(!connector_state->crtc))
                return -EINVAL;

-       connector_state->best_encoder = new_encoder;
+       set_best_encoder(state, connector_state, new_encoder);
+
        idx = drm_crtc_index(connector_state->crtc);

        crtc_state = state->crtc_states[idx];
diff --git a/drivers/gpu/drm/i915/intel_display.c 
b/drivers/gpu/drm/i915/intel_display.c
index d77968092ce4..2d9cc848f294 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -15604,6 +15604,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
                crtc->base.state->active = crtc->active;
                crtc->base.enabled = crtc->active;
                crtc->base.state->connector_mask = 0;
+               crtc->base.state->encoder_mask = 0;

                /* Because we only establish the connector -> encoder ->
                 * crtc links if something is active, this means the
@@ -15843,6 +15844,8 @@ static void intel_modeset_readout_hw_state(struct 
drm_device *dev)
                                 */
                                encoder->base.crtc->state->connector_mask |=
                                        1 << 
drm_connector_index(&connector->base);
+                               encoder->base.crtc->state->encoder_mask |=
+                                       1 << drm_encoder_index(&encoder->base);
                        }

                } else {
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index c0226f945d62..51287f36b214 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -307,6 +307,7 @@ struct drm_plane_helper_funcs;
  * @connectors_changed: connectors to this crtc have been updated
  * @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes
  * @connector_mask: bitmask of (1 << drm_connector_index(connector)) of 
attached connectors
+ * @encoder_mask: bitmask of (1 << drm_encoder_index(encoder)) of attached 
encoders
  * @last_vblank_count: for helpers and drivers to capture the vblank of the
  *     update to ensure framebuffer cleanup isn't done too early
  * @adjusted_mode: for use by helpers and drivers to compute adjusted mode 
timings
@@ -341,6 +342,7 @@ struct drm_crtc_state {
        u32 plane_mask;

        u32 connector_mask;
+       u32 encoder_mask;

        /* last_vblank_count: for vblank waits before cleanup */
        u32 last_vblank_count;

Reply via email to