On 21/05/2026 13:00, Borah, Chaitanya Kumar wrote:


On 5/20/2026 2:39 AM, Melissa Wen wrote:
Only allow updates on colorops that are part of an active pipeline.
Check if a colorop in a new state belongs to a color pipeline which was
set as a plane color_pipeline property and therefore is an active color
pipeline. If not, reject the atomic state. Performing this check later
in drm_atomic_check_only() to remove the ordering dependency that would
exist if done at the time of colorop property setting.

Suggested-by: Chaitanya Kumar Borah <[email protected]>
Signed-off-by: Melissa Wen <[email protected]>
---
  drivers/gpu/drm/drm_atomic.c | 38 ++++++++++++++++++++++++++++++++++++
  1 file changed, 38 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 28831a548b0c..659cf56150e5 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -812,6 +812,33 @@ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state,
      return 0;
  }
  +/**
+ * drm_atomic_colorop_check - check new colorop state
+ * @new_colorop_state: new colorop state to check
+ *
+ * Ensure that the colorop in @new_colorop_state belongs to an active color + * pipeline, i.e. it's in the chain of colorops set to the color_pipeline
+ * property of a plane state.
+ *
+ * Returns: 0 on success, -EINVAL otherwise.
+ */
+static int drm_atomic_colorop_check(const struct drm_colorop_state *new_colorop_state)
+{
+    struct drm_colorop *colorop, *color_pipeline;
+    struct drm_plane_state *new_plane_state;
+
+    new_plane_state = drm_atomic_get_new_plane_state(new_colorop_state->state,
+ new_colorop_state->colorop->plane);
+    color_pipeline = new_plane_state ? new_plane_state->color_pipeline :
+ new_colorop_state->colorop->plane->state->color_pipeline;
+
+    for (colorop = color_pipeline; colorop; colorop = colorop->next)
+        if (colorop == new_colorop_state->colorop)
+            return 0;
+
+    return -EINVAL;
+}
+

This causes regression in our CI[1].

I looked into it and looks like the following sequence in igt@kms_color_pipeline causes the error

        set_color_pipeline_bypass(plane);
        reset_colorops(colorops);
        igt_plane_set_fb(plane, NULL);
        igt_display_commit_atomic(&data->display, 0, NULL);

So this change restricts bypassing/disabling both the pipeline and a colorop within it in a single commit.

Also Sashiko had the following to say

"Furthermore, does this unnecessarily restrict UAPI by preventing userspace from configuring inactive pipelines before enabling them, or from resetting
properties on a pipeline in the same commit that switches away from it?"

So this will also fail a commit which tries to change a pipeline and disable the colorops in an old pipeline.

I wonder if userspace resetting colorops to disable a pipeline or configuring colorops before enabling the color pipeline is an expected behavior.

For resetting properties, I think I can solve it by taking into account old and new state to collect the active colorops, not only the new state. But if configuring colorops before activate a color pipeline is expected, there is no need to have patches 1 and 2, since setting an inactive colorop have to be allowed. In that case, the solution is just drop both patches from the series.

Melissa


That got me thinking whether the first patch[3] in the series is also correct, since it is quite similar to the change[4] I added, where colorops are only added to the state when a pipeline is active. In both cases, we could end up ignoring colorops that are not part of the currently selected pipeline.

[1] https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-166922v1/shard-lnl-5/igt@kms_color_pipeline@[email protected] [2] https://sashiko.dev/#/patchset/20260520073827.3395745-3-chaitanya.kumar.borah%40intel.com [3] https://lore.kernel.org/dri-devel/[email protected]/ [4] https://lore.kernel.org/dri-devel/[email protected]/

P.S. Can you please send the next version to intel-gfx and intel-xe too?

==
Chaitanya
  static void drm_atomic_colorop_print_state(struct drm_printer *p,
                         const struct drm_colorop_state *state)
  {
@@ -1665,6 +1692,8 @@ int drm_atomic_check_only(struct drm_atomic_commit *state)
      struct drm_plane *plane;
      struct drm_plane_state *old_plane_state;
      struct drm_plane_state *new_plane_state;
+    struct drm_colorop *colorop;
+    struct drm_colorop_state *new_colorop_state;
      struct drm_crtc *crtc;
      struct drm_crtc_state *old_crtc_state;
      struct drm_crtc_state *new_crtc_state;
@@ -1681,6 +1710,15 @@ int drm_atomic_check_only(struct drm_atomic_commit *state)
              requested_crtc |= drm_crtc_mask(crtc);
      }
  +    for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) {
+        ret = drm_atomic_colorop_check(new_colorop_state);
+        if (ret) {
+            drm_dbg_atomic(dev, "[COLOROP:%d:%d] is not part of an active color pipeline.\n",
+                       colorop->base.id, colorop->type);
+            return ret;
+        }
+    }
+
      for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {           ret = drm_atomic_plane_check(old_plane_state, new_plane_state);
          if (ret) {


Reply via email to