From: Maxime Ripard <mripard@kernel.org>
To: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>,
Thomas Zimmermann <tzimmermann@suse.de>,
David Airlie <airlied@gmail.com>,
Simona Vetter <simona@ffwll.ch>,
Louis Chauvet <louis.chauvet@bootlin.com>,
Haneen Mohammed <hamohammed.sa@gmail.com>,
Melissa Wen <melissa.srw@gmail.com>
Cc: "Daniel Stone" <daniels@collabora.com>,
"Harry Wentland" <harry.wentland@amd.com>,
"Jocelyn Falempe" <jfalempe@redhat.com>,
"Jonas Ådahl" <jadahl@redhat.com>,
"Michel Dänzer" <mdaenzer@redhat.com>,
"Pekka Paalanen" <pekka.paalanen@collabora.com>,
"Sebastian Wick" <sebastian.wick@redhat.com>,
"Simon Ser" <contact@emersion.fr>,
"Victoria Brekenfeld" <victoria@system76.com>,
"Xaver Hugl" <xaver.hugl@kde.org>,
dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
"Maxime Ripard" <mripard@kernel.org>,
"Daniel Stone" <daniel@fooishbar.org>
Subject: [PATCH v7 13/16] drm/tests: atomic: Add tests for drm_atomic_commit_fill_with_defaults()
Date: Fri, 30 Oct 2026 11:27:45 +0100 [thread overview]
Message-ID: <20261030-drm-reset-state-flag-v7-13-4e55eaeae683@kernel.org> (raw)
In-Reply-To: <20261030-drm-reset-state-flag-v7-0-4e55eaeae683@kernel.org>
drm_atomic_commit_fill_with_defaults() is used by the
DRM_MODE_ATOMIC_RESET flag to bring all objects back to their pristine
state. However, it has no dedicated test coverage.
Add two tests that verify the reset cycle. The first enables a CRTC,
plane, and connector, then calls drm_atomic_commit_fill_with_defaults()
and verifies all objects return to their disabled state: CRTC inactive,
plane disabled with no framebuffer, and connector unbound. The second
goes further and commits the default-filled state to verify the
init -> enable -> reset -> commit sequence completes without errors.
Suggested-by: Daniel Stone <daniel@fooishbar.org>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/tests/drm_atomic_test.c | 313 +++++++++++++++++++++++++++++++-
1 file changed, 311 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/tests/drm_atomic_test.c b/drivers/gpu/drm/tests/drm_atomic_test.c
index 5e156d09e56f..160de1aa3ec2 100644
--- a/drivers/gpu/drm/tests/drm_atomic_test.c
+++ b/drivers/gpu/drm/tests/drm_atomic_test.c
@@ -9,4 +9,5 @@
#include <drm/drm_kunit_helpers.h>
#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_property.h>
#include <kunit/test.h>
@@ -143,5 +144,4 @@ static struct kunit_case drm_atomic_get_connector_for_encoder_tests[] = {
};
-
static struct kunit_suite drm_atomic_get_connector_for_encoder_test_suite = {
.name = "drm_test_atomic_get_connector_for_encoder",
@@ -149,5 +149,314 @@ static struct kunit_suite drm_atomic_get_connector_for_encoder_test_suite = {
};
-kunit_test_suite(drm_atomic_get_connector_for_encoder_test_suite);
+/*
+ * Test that after enabling a CRTC and connector, filling with defaults
+ * produces a state where all objects are disabled: CRTC is inactive,
+ * plane is disabled, and connector is unbound.
+ *
+ * This is done without any lease, so all objects are expected to be
+ * reset.
+ *
+ * The plane is not explicitly enabled with a framebuffer here, so
+ * this validates that fill_with_defaults produces a consistent
+ * disabled state rather than testing an active plane teardown.
+ */
+static void drm_test_check_fill_with_defaults(struct kunit *test)
+{
+ struct drm_atomic_test_priv *priv;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_connector_state *new_conn_state;
+ struct drm_crtc_state *new_crtc_state;
+ struct drm_plane_state *new_plane_state;
+ struct drm_atomic_commit *state;
+ struct drm_display_mode *mode;
+ struct drm_device *drm;
+ int ret;
+
+ priv = create_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
+
+ drm = &priv->drm;
+
+ mode = drm_kunit_display_mode_from_cea_vic(test, drm, 16);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+retry_enable:
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ priv->crtc,
+ &priv->connector,
+ mode, &ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_enable;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+retry_fill:
+ ret = drm_atomic_commit_fill_with_defaults(NULL, state);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_fill;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ new_crtc_state = drm_atomic_get_new_crtc_state(state, priv->crtc);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_crtc_state);
+ KUNIT_EXPECT_FALSE(test, new_crtc_state->enable);
+ KUNIT_EXPECT_FALSE(test, new_crtc_state->active);
+
+ new_plane_state = drm_atomic_get_new_plane_state(state, priv->plane);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_plane_state);
+ KUNIT_EXPECT_NULL(test, new_plane_state->crtc);
+ KUNIT_EXPECT_NULL(test, new_plane_state->fb);
+
+ new_conn_state = drm_atomic_get_new_connector_state(state, &priv->connector);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
+ KUNIT_EXPECT_NULL(test, new_conn_state->crtc);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+}
+
+/*
+ * Test that after enabling a CRTC and connector, fill_with_defaults
+ * produces a state that can be successfully committed.
+ *
+ * This is done without any lease, so all objects are reset.
+ *
+ * The plane is not explicitly enabled with a framebuffer, so this
+ * validates that fill_with_defaults produces a consistent disabled
+ * state rather than testing an active plane teardown.
+ */
+static void drm_test_check_fill_with_defaults_commit(struct kunit *test)
+{
+ struct drm_atomic_test_priv *priv;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_atomic_commit *state;
+ struct drm_display_mode *mode;
+ struct drm_device *drm;
+ int ret;
+
+ priv = create_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
+
+ drm = &priv->drm;
+
+ mode = drm_kunit_display_mode_from_cea_vic(test, drm, 16);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+retry_enable:
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ priv->crtc,
+ &priv->connector,
+ mode, &ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_enable;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+retry_fill:
+ ret = drm_atomic_commit_fill_with_defaults(NULL, state);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_fill;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ state->allow_modeset = true;
+
+ ret = drm_atomic_commit(state);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_fill;
+ }
+ KUNIT_EXPECT_EQ(test, ret, 0);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+}
+
+/*
+ * Test that filling with defaults reports the color management changes
+ * on the new states through color_mgmt_changed, so that drivers
+ * reprogram the color management hardware when a LUT is being cleared
+ * by the reset.
+ */
+static void drm_test_check_fill_with_defaults_color_mgmt(struct kunit *test)
+{
+ struct drm_atomic_test_priv *priv;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_crtc_state *new_crtc_state;
+ struct drm_plane_state *new_plane_state;
+ struct drm_atomic_commit *state;
+ struct drm_property_blob *gamma_lut;
+ struct drm_device *drm;
+ u32 lut = 0;
+ int ret;
+
+ priv = create_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
+
+ drm = &priv->drm;
+
+ gamma_lut = drm_property_create_blob(drm, sizeof(lut), &lut);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, gamma_lut);
+
+ /*
+ * Attach a gamma LUT to the current CRTC state, like userspace
+ * setting the GAMMA_LUT property would. The state takes ownership
+ * of the blob reference.
+ */
+ priv->crtc->state->gamma_lut = gamma_lut;
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+ state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+retry_fill:
+ ret = drm_atomic_commit_fill_with_defaults(NULL, state);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_fill;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ new_crtc_state = drm_atomic_get_new_crtc_state(state, priv->crtc);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_crtc_state);
+ KUNIT_EXPECT_NULL(test, new_crtc_state->gamma_lut);
+ KUNIT_EXPECT_TRUE(test, new_crtc_state->color_mgmt_changed);
+
+ new_plane_state = drm_atomic_get_new_plane_state(state, priv->plane);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_plane_state);
+ KUNIT_EXPECT_FALSE(test, new_plane_state->color_mgmt_changed);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+}
+
+/*
+ * Test that a reset on which userspace re-applies the exact same
+ * configuration doesn't need a modeset, and thus doesn't require the
+ * DRM_MODE_ATOMIC_ALLOW_MODESET flag.
+ */
+static void drm_test_check_fill_with_defaults_no_modeset(struct kunit *test)
+{
+ struct drm_atomic_test_priv *priv;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_crtc_state *new_crtc_state;
+ struct drm_connector_state *new_conn_state;
+ struct drm_atomic_commit *state;
+ struct drm_display_mode *mode;
+ struct drm_device *drm;
+ int ret;
+
+ priv = create_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
+
+ drm = &priv->drm;
+
+ mode = drm_kunit_display_mode_from_cea_vic(test, drm, 16);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+retry_enable:
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ priv->crtc,
+ &priv->connector,
+ mode, &ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_enable;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+retry:
+ ret = drm_atomic_commit_fill_with_defaults(NULL, state);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ /* Re-apply the exact same configuration on top of the reset */
+ new_conn_state = drm_atomic_get_new_connector_state(state, &priv->connector);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
+
+ ret = drm_atomic_set_crtc_for_connector(new_conn_state, priv->crtc);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ new_crtc_state = drm_atomic_get_new_crtc_state(state, priv->crtc);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_crtc_state);
+
+ ret = drm_atomic_set_mode_for_crtc(new_crtc_state, mode);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ new_crtc_state->enable = true;
+ new_crtc_state->active = true;
+
+ /* Modesets aren't allowed and shouldn't be needed */
+ state->allow_modeset = false;
+
+ ret = drm_atomic_check_only(state);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry;
+ }
+ KUNIT_EXPECT_EQ(test, ret, 0);
+
+ KUNIT_EXPECT_FALSE(test, new_crtc_state->active_changed);
+ KUNIT_EXPECT_FALSE(test, new_crtc_state->connectors_changed);
+ KUNIT_EXPECT_FALSE(test, new_crtc_state->mode_changed);
+ KUNIT_EXPECT_FALSE(test, drm_atomic_crtc_needs_modeset(new_crtc_state));
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+}
+
+static struct kunit_case drm_atomic_fill_with_defaults_tests[] = {
+ KUNIT_CASE(drm_test_check_fill_with_defaults),
+ KUNIT_CASE(drm_test_check_fill_with_defaults_commit),
+ KUNIT_CASE(drm_test_check_fill_with_defaults_color_mgmt),
+ KUNIT_CASE(drm_test_check_fill_with_defaults_no_modeset),
+ { }
+};
+
+static struct kunit_suite drm_atomic_fill_with_defaults_test_suite = {
+ .name = "drm_atomic_commit_fill_with_defaults",
+ .test_cases = drm_atomic_fill_with_defaults_tests,
+};
+
+kunit_test_suites(&drm_atomic_get_connector_for_encoder_test_suite,
+ &drm_atomic_fill_with_defaults_test_suite);
MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
--
2.55.0
next prev parent reply other threads:[~2026-10-30 10:28 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-30 10:27 [PATCH v7 00/16] drm: Add DRM_MODE_ATOMIC_RESET flag Maxime Ripard
2026-10-30 10:27 ` [PATCH v7 01/16] drm/amd/display: Fix planes atomic_create_state implementation Maxime Ripard
2026-10-30 10:27 ` [PATCH v7 02/16] drm/solomon: ssd130x: Drop the init-only assumption in ssd130x_crtc_create_state() Maxime Ripard
2026-10-30 10:39 ` Javier Martinez Canillas
2026-10-30 10:27 ` [PATCH v7 03/16] drm/atomic: Switch to krealloc_array() in drm_atomic_get_private_obj_state() Maxime Ripard
2026-10-30 10:27 ` [PATCH v7 04/16] drm/atomic: Use __GFP_ZERO instead of explicit memset " Maxime Ripard
2026-10-30 10:27 ` [PATCH v7 05/16] drm/atomic: Use __GFP_ZERO instead of explicit memset in drm_atomic_get_connector_state() Maxime Ripard
2026-10-30 10:27 ` [PATCH v7 06/16] drm/atomic: Create function to insert CRTC state into a commit Maxime Ripard
2026-10-30 10:27 ` [PATCH v7 07/16] drm/atomic: Create function to insert plane " Maxime Ripard
2026-10-30 10:27 ` [PATCH v7 08/16] drm/atomic: Create function to insert colorop " Maxime Ripard
2026-10-30 10:27 ` [PATCH v7 09/16] drm/atomic: Create function to insert private obj " Maxime Ripard
2026-10-30 10:27 ` [PATCH v7 10/16] drm/atomic: Create function to insert connector " Maxime Ripard
2026-10-30 10:27 ` [PATCH v7 11/16] drm/atomic: Add drm_atomic_implements_create_state() helper Maxime Ripard
2026-10-30 10:27 ` [PATCH v7 12/16] drm/atomic: Allow filling a commit with pristine object states Maxime Ripard
2026-10-30 10:53 ` sashiko-bot
2026-10-30 10:27 ` Maxime Ripard [this message]
2026-10-30 10:39 ` [PATCH v7 13/16] drm/tests: atomic: Add tests for drm_atomic_commit_fill_with_defaults() sashiko-bot
2026-10-30 10:27 ` [PATCH v7 14/16] drm/atomic-uapi: Add DRM_MODE_ATOMIC_RESET flag Maxime Ripard
2026-10-30 10:54 ` sashiko-bot
2026-10-30 10:27 ` [PATCH v7 15/16] drm/vkms: Switch container_of helpers to container_of_const Maxime Ripard
2026-10-30 10:27 ` [PATCH v7 16/16] drm/vkms: Add driver-specific plane property for testing Maxime Ripard
2026-10-30 10:40 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261030-drm-reset-state-flag-v7-13-4e55eaeae683@kernel.org \
--to=mripard@kernel.org \
--cc=airlied@gmail.com \
--cc=contact@emersion.fr \
--cc=daniel@fooishbar.org \
--cc=daniels@collabora.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=hamohammed.sa@gmail.com \
--cc=harry.wentland@amd.com \
--cc=jadahl@redhat.com \
--cc=jfalempe@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=louis.chauvet@bootlin.com \
--cc=maarten.lankhorst@linux.intel.com \
--cc=mdaenzer@redhat.com \
--cc=melissa.srw@gmail.com \
--cc=pekka.paalanen@collabora.com \
--cc=sebastian.wick@redhat.com \
--cc=simona@ffwll.ch \
--cc=tzimmermann@suse.de \
--cc=victoria@system76.com \
--cc=xaver.hugl@kde.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.