* [PATCH v8 0/7] drm: Add DRM_MODE_ATOMIC_RESET flag
@ 2026-11-06 15:11 Maxime Ripard
2026-11-06 15:11 ` [PATCH v8 1/7] drm/amd/display: Fix planes atomic_create_state implementation Maxime Ripard
` (6 more replies)
0 siblings, 7 replies; 8+ messages in thread
From: Maxime Ripard @ 2026-11-06 15:11 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie,
Simona Vetter, Louis Chauvet, Haneen Mohammed, Melissa Wen
Cc: Daniel Stone, Harry Wentland, Jocelyn Falempe, Jonas Ådahl,
Michel Dänzer, Pekka Paalanen, Sebastian Wick, Simon Ser,
Victoria Brekenfeld, Xaver Hugl, dri-devel, linux-kernel,
Maxime Ripard, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, amd-gfx, Daniel Stone
Hi,
Userspace currently has no atomic way to bring a display pipeline back
to a pristine state. A compositor that wants to start from a known
baseline must explicitly set every property on every KMS object to its
default value, which requires tracking which properties exist and what
their defaults are. This is fragile and must be updated every time a
new property is added to the kernel.
This series introduces a new DRM_MODE_ATOMIC_RESET flag for the
atomic ioctl. When set, the kernel fills the commit with default
states for all KMS objects before applying the properties supplied in
the request. Properties not explicitly included remain at their
defaults. This allows userspace to describe the desired end state
declaratively, without caring about the current state or the full set
of properties.
The bulk of the series extracts the state insertion logic from each
drm_atomic_get_*_state() into standalone helpers, since the
fill_with_defaults path creates states through atomic_create_state()
rather than atomic_duplicate_state() and cannot reuse the existing
functions directly.
A driver-specific property is added to vkms planes for testing.
Standard properties are impractical for this: compositors like Mutter
enumerate all known properties, making it hard to isolate the reset
behavior in a test.
Mutter has a working implementation using the new flag, with a
vkms-based test exercising the reset behavior:
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/5309
And we have IGT tests as well:
https://lore.kernel.org/r/20261030105135.268065-1-mripard@kernel.org
This series relies on all drivers implementing atomic_create_state.
The conversion is in progress but not yet complete.
Let me know what you think,
Maxime
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
Changes in v8:
- Fix more leases issues
- Drop applied patches
- Link to v7: https://lore.kernel.org/r/20261030-drm-reset-state-flag-v7-0-4e55eaeae683@kernel.org
Changes in v7:
- Fix a whole bunch of sashiko issues to deal with color_mgmt_changed,
leases, partially leased devices (like a plane leased but it's crtc
isn't) and the interaction with PAGE_FLIP_EVENT better
- Fix crtc create_state implementation for ssd130x
- Actually make it possible for a compositor to recreate the same whole
state without passing ALLOW_MODESET
- Fix EDEADLK bugs with kunit tests
- Don't report DRM_CAP_ATOMIC_RESET on !atomic drivers
- Fix error handling in vkms for the new property
- Add more kunit tests for the new corner cases
- Link to v6: https://lore.kernel.org/r/20261022-drm-reset-state-flag-v6-0-f36d640b7e76@kernel.org
Changes in v6:
- If using a lease, only considered the leased objects
- Fix amdgpu plane atomic_create_state implementation
- Link to v5: https://lore.kernel.org/r/20261016-drm-reset-state-flag-v5-0-dad2d64b693b@kernel.org
Changes in v5:
- Fix bisection issue
- Improve the documentation
- Fix connector hotplugging issue
- Added kunit tests for drm_atomic_commit_fill_with_defaults()
- Link to v4: https://lore.kernel.org/r/20260918-drm-reset-state-flag-v4-0-5ad106370f05@kernel.org
Changes in v4:
- Improve the drm_atomic_get_private_obj_state and
drm_atomic_get_connector_state array reallocations
- Return void on functions to insert an object state into a commit when
it cannot fail
- Rename drm_atomic_can_create_state() into
drm_atomic_implements_create_state()
- Move capability check from drm_atomic_commit_fill_with_defaults to its
caller
- Added IGT test
- Link to v3: https://lore.kernel.org/r/20260908-drm-reset-state-flag-v3-0-905570f387a4@kernel.org
Changes in v3:
- Rebased on top of the latest atomic_create_state series
- Sebastian Wick created and tested this work with mutter and vkms
- Fix colorop locking
- Link to v2: https://lore.kernel.org/r/20260812-drm-reset-state-flag-v2-0-e96ce13317dd@kernel.org
Changes in v2:
- Fix bisection
- Add capability to let userspace know if it can reset the state
- Link to v1: https://lore.kernel.org/r/20260708-drm-reset-state-flag-v1-0-c37dc985485d@kernel.org
---
Maxime Ripard (6):
drm/amd/display: Fix planes atomic_create_state implementation
drm/atomic: Add drm_atomic_implements_create_state() helper
drm/lease: Add a helper to tell whether a lease was revoked
drm/atomic: Allow filling a commit with pristine object states
drm/tests: atomic: Add tests for drm_atomic_commit_fill_with_defaults()
drm/vkms: Add driver-specific plane property for testing
Sebastian Wick (1):
drm/atomic-uapi: Add DRM_MODE_ATOMIC_RESET flag
.../drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c | 3 -
drivers/gpu/drm/drm_atomic.c | 407 +++++++++++++++++++++
drivers/gpu/drm/drm_atomic_uapi.c | 44 ++-
drivers/gpu/drm/drm_ioctl.c | 5 +
drivers/gpu/drm/drm_lease.c | 26 ++
drivers/gpu/drm/tests/drm_atomic_test.c | 322 +++++++++++++++-
drivers/gpu/drm/vkms/vkms_drv.h | 3 +
drivers/gpu/drm/vkms/vkms_plane.c | 63 +++-
include/drm/drm_atomic.h | 4 +
include/drm/drm_lease.h | 2 +
include/uapi/drm/drm.h | 10 +
include/uapi/drm/drm_mode.h | 17 +-
12 files changed, 895 insertions(+), 11 deletions(-)
---
base-commit: d2a8cee91bfa8616f713c7c8f539a81e8e3554ea
change-id: 20260708-drm-reset-state-flag-2fb2b5711f97
prerequisite-message-id: 20261105-drm-no-more-config-reset-v1-0-1f58d1e33380@kernel.org
prerequisite-patch-id: 3fd105fbfdbb4eee1f8ae9682b359477d5c2d610
prerequisite-patch-id: ed1d1dd244e64b18c5682800b546ebb2d0f44ec8
prerequisite-patch-id: 6b00324107d28bfe6ccd346730c6370d8f8362c4
prerequisite-patch-id: bac8bfa53c3c77a832500f711322530e39d26c74
prerequisite-patch-id: 60002e0ea0141b4051f2062152244b545450ffdf
prerequisite-patch-id: a82ef0b22909efd3a2f1a779e27ad60b08554203
prerequisite-patch-id: 4d4db6fb993ce12a03f5f22e07b060defc28b7d8
prerequisite-patch-id: 7a716ac0b6df5a2d9423bfa09457e7c2ae11e35f
prerequisite-patch-id: 35c60176b5a45a76a30285767fba4f83c5059868
prerequisite-patch-id: 23ef4052a7a932ec4611b640d4323e0f93760a6d
prerequisite-patch-id: f6a08bc40145c9a61508a37fe632e007c58566b9
prerequisite-patch-id: 942ec51b8579c4a7d5652d390dbcaa6fe1ef35bb
prerequisite-patch-id: cac9b8740c50ed002bdb7df8471c4493a53948b0
prerequisite-patch-id: 083d50c81b3609bc6756a2b9c89b30c5918dbcd3
prerequisite-patch-id: 97dd764d28e34d6c1fd346602931c1688aa4fe8d
prerequisite-patch-id: 566c8a35a9734a8e8a254afcc0fbd9765c980334
prerequisite-patch-id: a2ae7568eef2833217f55eb9528e2f846c73f993
prerequisite-patch-id: 4bdc653ad663151585ed7d71ed9f70ac702301fa
prerequisite-patch-id: ee3f427f087dde1290f0c0a3e821379427552961
prerequisite-patch-id: d14cd6008b88c7c9b61ca5241c961c4747a6fdfe
prerequisite-patch-id: c642e4fcebdbfc0ab86bba68c957ad5bbe62ef58
prerequisite-patch-id: 71afb7db95568dfa686ab670039ba60faeb91914
prerequisite-patch-id: 6557c88b83cd8d2ded0e4d70378c9a868659fea0
prerequisite-patch-id: 4020d12428794416f75edb398d84a6a14905f588
prerequisite-patch-id: a4806b41921baa3b8a3039d5431e099138fe6fa6
prerequisite-patch-id: 7a742e65aa5d69a733376641d0eb45281239b866
prerequisite-patch-id: ba3e625c15aa8e34747292c95ea9158b0cb98b34
prerequisite-patch-id: ba92010fead3c007e2cbaeb15bce922eb304ccac
prerequisite-patch-id: 2fc97bb7478092919001b21d2455a73373a5ba73
prerequisite-patch-id: 97a28c8af17b043429e3b40325576f74518ff802
prerequisite-patch-id: 37ae6417556eea439aab01725cfd920c1107e630
prerequisite-patch-id: 3f8725771832d7cccd8c88a33b4fac362a2a1221
prerequisite-patch-id: 5d51033ca88aa46e8347396cdc17fd5473636c13
prerequisite-patch-id: 983be3e35801efe3052f0983d728a9703e7ded88
prerequisite-patch-id: 20f874f2f1b44d9a27824a2e3944477fc3c02af5
prerequisite-patch-id: fc7f1510621f228d42bf1666c06f34926f3e10f4
prerequisite-patch-id: b9e987299142a89ca3a7bfb5b0335a215c7cdd52
prerequisite-patch-id: 1d11dea3090f6b72322c3827bd260ed3d12e1201
prerequisite-patch-id: 4182aa31cbc4b985e3a628c3dc9a2fd039188f7e
prerequisite-patch-id: 7b7f07b1c57398f185a93d6b3212394753292be7
prerequisite-patch-id: e6bd5afbc9593e93203caa0ae9f08545511e2bf2
prerequisite-patch-id: c6d466588800f94684ebf9fb785ce085510c8f93
prerequisite-patch-id: 5f8a9d6fd20c05d708df6424102575251d32331f
prerequisite-patch-id: 18c2d823dc5b44514c0b2278986933a1a9834f02
prerequisite-patch-id: a8c4944302cbea92690957fd18162ca303757874
prerequisite-patch-id: 962e6cc26e53a3319302fd4c2aae2bc4b593f4be
prerequisite-patch-id: 366fc63bc744ea4a2af4f16befaa1d7e8c66bf84
prerequisite-patch-id: 33c4fd1e1ccd1eac9fde961a0f7ed8509e713c7e
prerequisite-patch-id: 496318ad0a87ec138780d4a50a2f8a49ca126ca6
prerequisite-patch-id: f85ec023f5ab9903987d867c330bde94b3c24c55
prerequisite-patch-id: 34fc06cb69e34ec4d67015187969e8d2c0c56660
prerequisite-patch-id: 3b789a4e47c47f855c44c125a75de3a79709d411
prerequisite-patch-id: b03787ca5a3d60d4ad5682313424a114c1862fb0
prerequisite-patch-id: 4ec079edf0025f849b1b8c7e3beb47db057ab6d2
prerequisite-patch-id: b44382d38528c92150f2d7cac5722cf8e09c0fab
prerequisite-patch-id: 02e42a505f17dbf5bc3e85b55d5df716e3819141
prerequisite-patch-id: faf2c686c253faa5a81801f78ba955d3ae8c0c4f
prerequisite-patch-id: 6407fec511e4d3bf785c3be581b828abac884ba7
prerequisite-patch-id: 1a9fc394fdf6b19434652a4c137a0ea819702325
prerequisite-patch-id: 6de415eec4ab2f2b8dec1f194fb89cfe01568f9b
prerequisite-patch-id: 73e1360c2be46882c0ca58d6d60f0c394f1d47f4
prerequisite-patch-id: fada6f5ef59f7119d5b202b64ce2184795428d7c
prerequisite-patch-id: 7f31438e1f326350688f7aa7169038a7a33b4ddc
prerequisite-patch-id: a9940a88c19f95573008a9e2bd950a43c12b7e3c
prerequisite-patch-id: 2d5e46c029b523f6d6f13a0716e56267691757cf
prerequisite-patch-id: 7aa60266913380f85e46f8dc71885356e3d7902a
prerequisite-patch-id: cd12813a72a4c558660f8f8d093928533ddbf5ee
prerequisite-patch-id: 186129fe8188f5b7cb6fef2701400fc6772aaf2e
prerequisite-patch-id: c99a84af1b60e1c8f80168706f5ed600a6eb4553
prerequisite-patch-id: 598515adbecc5c14e8ffe631206a906fb2c9f59c
prerequisite-patch-id: cf84de09ca65f4577268e9a4a8a166436735b7da
prerequisite-patch-id: cfd9ec749b0f3c78e0a64a73756f978bfd853391
prerequisite-patch-id: 87104eb556b1cef43ded0979f0b806f35ec819bb
prerequisite-patch-id: 5536c46e78e53cc31224b2730ca5fb454cd17761
prerequisite-patch-id: 48e3546e357a8e68e4abaeb2faf1081afb8f3ae3
prerequisite-patch-id: be78356c5aabcd0e68c61b2bc785c73a0c2edff9
prerequisite-patch-id: 7192a8aa88903ca758655dea8eaac94b98481e82
prerequisite-patch-id: f28910d02bfc6e11c1ecc2ce03db57ccaba0d185
prerequisite-patch-id: 48fc2a91c98aac131457deed8d9c2965eaffd1fb
prerequisite-patch-id: 0c829edd4d3d8cb4765d649411dec1124fd20fbd
prerequisite-patch-id: e994569657dc0537d6d3b9f7cd4d919ba2602126
prerequisite-patch-id: bce46caeb9616651be519c0474855ce9341de611
prerequisite-patch-id: a2a70a62d2684c072e3927abeb7a9e86dbec759b
Best regards,
--
Maxime Ripard <mripard@kernel.org>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v8 1/7] drm/amd/display: Fix planes atomic_create_state implementation
2026-11-06 15:11 [PATCH v8 0/7] drm: Add DRM_MODE_ATOMIC_RESET flag Maxime Ripard
@ 2026-11-06 15:11 ` Maxime Ripard
2026-11-06 15:11 ` [PATCH v8 2/7] drm/atomic: Add drm_atomic_implements_create_state() helper Maxime Ripard
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Maxime Ripard @ 2026-11-06 15:11 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie,
Simona Vetter, Louis Chauvet, Haneen Mohammed, Melissa Wen
Cc: Daniel Stone, Harry Wentland, Jocelyn Falempe, Jonas Ådahl,
Michel Dänzer, Pekka Paalanen, Sebastian Wick, Simon Ser,
Victoria Brekenfeld, Xaver Hugl, dri-devel, linux-kernel,
Maxime Ripard, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, amd-gfx
Commit 2bcec01cf105 ("drm/amdgpu_dm: Convert to atomic_create_state")
converted the amdgpu planes to use atomic_create_state instead of reset.
Unlike reset, atomic_create_state is meant to allocate a new default
state without any side effect on the hardware or software state.
However, during the conversion we forgot to remove the call to destroy
the existing plane state if any. While this was expected from a reset
implementation, it's not for an atomic_create_state one. Remove it.
Fixes: 2bcec01cf105 ("drm/amdgpu_dm: Convert to atomic_create_state")
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
To: Harry Wentland <harry.wentland@amd.com>
To: Leo Li <sunpeng.li@amd.com>
To: Rodrigo Siqueira <siqueira@igalia.com>
To: Alex Deucher <alexander.deucher@amd.com>
To: Christian König <christian.koenig@amd.com>
Cc: amd-gfx@lists.freedesktop.org
---
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
index 91398230d408..31101c810bac 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
@@ -1804,7 +1804,4 @@ STATIC_IFN_KUNIT struct drm_plane_state *amdgpu_dm_plane_drm_plane_create_state(
}
- if (plane->state)
- plane->funcs->atomic_destroy_state(plane, plane->state);
-
__drm_atomic_helper_plane_state_init(&amdgpu_state->base, plane);
amdgpu_state->degamma_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT;
--
2.55.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v8 2/7] drm/atomic: Add drm_atomic_implements_create_state() helper
2026-11-06 15:11 [PATCH v8 0/7] drm: Add DRM_MODE_ATOMIC_RESET flag Maxime Ripard
2026-11-06 15:11 ` [PATCH v8 1/7] drm/amd/display: Fix planes atomic_create_state implementation Maxime Ripard
@ 2026-11-06 15:11 ` Maxime Ripard
2026-11-06 15:11 ` [PATCH v8 3/7] drm/lease: Add a helper to tell whether a lease was revoked Maxime Ripard
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Maxime Ripard @ 2026-11-06 15:11 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie,
Simona Vetter, Louis Chauvet, Haneen Mohammed, Melissa Wen
Cc: Daniel Stone, Harry Wentland, Jocelyn Falempe, Jonas Ådahl,
Michel Dänzer, Pekka Paalanen, Sebastian Wick, Simon Ser,
Victoria Brekenfeld, Xaver Hugl, dri-devel, linux-kernel,
Maxime Ripard
The atomic reset path will need to create pristine default states from
scratch for every plane, CRTC, and connector. This requires all of them
to implement the atomic_create_state hook.
Introduce a drm_atomic_implements_create_state() helper that iterates
over all planes, CRTCs, and connectors and returns whether they all
provide the hook. Color operations are excluded since they always use
drm_atomic_helper_colorop_create_state() directly.
This will be used both as a precondition before filling a commit with
default states, and to report the device capability to userspace.
Reviewed-by: Daniel Stone <daniels@collabora.com>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic.c | 49 ++++++++++++++++++++++++++++++++++++++++++++
include/drm/drm_atomic.h | 2 ++
2 files changed, 51 insertions(+)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 81591173265d..7a77051096c9 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -1601,4 +1601,53 @@ drm_atomic_get_new_bridge_state(const struct drm_atomic_commit *state,
EXPORT_SYMBOL(drm_atomic_get_new_bridge_state);
+/**
+ * drm_atomic_implements_create_state - check if a device supports creating pristine states
+ * @dev: DRM device
+ *
+ * Check whether every plane, CRTC, and connector in @dev implements the
+ * &drm_plane_funcs.atomic_create_state, &drm_crtc_funcs.atomic_create_state,
+ * and &drm_connector_funcs.atomic_create_state hooks respectively. These hooks
+ * are required to create default states from scratch rather than duplicating
+ * the current state.
+ *
+ * Color operations are not checked because they always use
+ * drm_atomic_helper_colorop_create_state() and do not have a per-driver hook.
+ *
+ * Returns:
+ * True if all objects implement atomic_create_state, false otherwise.
+ */
+bool drm_atomic_implements_create_state(struct drm_device *dev)
+{
+ struct drm_connector_list_iter conn_iter;
+ struct drm_connector *connector;
+ struct drm_plane *plane;
+ struct drm_crtc *crtc;
+
+ /*
+ * colorops don't have an atomic_create_state hook but
+ * drm_atomic_helper_colorop_create_state()
+ */
+
+ drm_for_each_plane(plane, dev)
+ if (!plane->funcs->atomic_create_state)
+ return false;
+
+ drm_for_each_crtc(crtc, dev)
+ if (!crtc->funcs->atomic_create_state)
+ return false;
+
+ drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_for_each_connector_iter(connector, &conn_iter) {
+ if (!connector->funcs->atomic_create_state) {
+ drm_connector_list_iter_end(&conn_iter);
+ return false;
+ }
+ }
+ drm_connector_list_iter_end(&conn_iter);
+
+ return true;
+}
+EXPORT_SYMBOL(drm_atomic_implements_create_state);
+
/**
* drm_atomic_add_encoder_bridges - add bridges attached to an encoder
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 3ae35b09c0cf..72c3d420f40c 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -703,4 +703,6 @@ drm_atomic_commit_alloc(struct drm_device *dev);
void drm_atomic_commit_clear(struct drm_atomic_commit *state);
+bool drm_atomic_implements_create_state(struct drm_device *dev);
+
/**
* drm_atomic_commit_get - acquire a reference to the atomic state
--
2.55.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v8 3/7] drm/lease: Add a helper to tell whether a lease was revoked
2026-11-06 15:11 [PATCH v8 0/7] drm: Add DRM_MODE_ATOMIC_RESET flag Maxime Ripard
2026-11-06 15:11 ` [PATCH v8 1/7] drm/amd/display: Fix planes atomic_create_state implementation Maxime Ripard
2026-11-06 15:11 ` [PATCH v8 2/7] drm/atomic: Add drm_atomic_implements_create_state() helper Maxime Ripard
@ 2026-11-06 15:11 ` Maxime Ripard
2026-11-06 15:11 ` [PATCH v8 4/7] drm/atomic: Allow filling a commit with pristine object states Maxime Ripard
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Maxime Ripard @ 2026-11-06 15:11 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie,
Simona Vetter, Louis Chauvet, Haneen Mohammed, Melissa Wen
Cc: Daniel Stone, Harry Wentland, Jocelyn Falempe, Jonas Ådahl,
Michel Dänzer, Pekka Paalanen, Sebastian Wick, Simon Ser,
Victoria Brekenfeld, Xaver Hugl, dri-devel, linux-kernel,
Maxime Ripard
drm_lease_held() only answers whether a given object is part of a lease,
and the answer can change from one call to the next. Code that needs to
look at several objects in a row has no way to tell whether the lease it
has been checking against is still around by the time it is done.
Add a helper reporting whether a lease has been revoked, so that such
code can bail out instead of acting on a lease that went away.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_lease.c | 26 ++++++++++++++++++++++++++
include/drm/drm_lease.h | 2 ++
2 files changed, 28 insertions(+)
diff --git a/drivers/gpu/drm/drm_lease.c b/drivers/gpu/drm/drm_lease.c
index 5d2cf724cbd7..dd59df14dcc0 100644
--- a/drivers/gpu/drm/drm_lease.c
+++ b/drivers/gpu/drm/drm_lease.c
@@ -148,4 +148,30 @@ bool drm_lease_held(struct drm_file *file_priv, int id)
}
+/*
+ * Checks whether the file is a lessee whose lease has been revoked. A
+ * lease is always revoked as a whole, so an empty one has been revoked.
+ */
+bool drm_lease_revoked(struct drm_file *file_priv)
+{
+ struct drm_master *master;
+ bool ret = false;
+
+ if (!file_priv)
+ return false;
+
+ master = drm_file_get_master(file_priv);
+ if (!master)
+ return false;
+
+ if (master->lessor) {
+ mutex_lock(&master->dev->mode_config.idr_mutex);
+ ret = idr_is_empty(&master->leases);
+ mutex_unlock(&master->dev->mode_config.idr_mutex);
+ }
+
+ drm_master_put(&master);
+ return ret;
+}
+
/*
* Given a bitmask of crtcs to check, reconstructs a crtc mask based on the
diff --git a/include/drm/drm_lease.h b/include/drm/drm_lease.h
index 53545b4ca9ef..03f7ea36c37c 100644
--- a/include/drm/drm_lease.h
+++ b/include/drm/drm_lease.h
@@ -21,4 +21,6 @@ bool drm_lease_held(struct drm_file *file_priv, int id);
bool _drm_lease_held(struct drm_file *file_priv, int id);
+bool drm_lease_revoked(struct drm_file *file_priv);
+
void drm_lease_revoke(struct drm_master *master);
--
2.55.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v8 4/7] drm/atomic: Allow filling a commit with pristine object states
2026-11-06 15:11 [PATCH v8 0/7] drm: Add DRM_MODE_ATOMIC_RESET flag Maxime Ripard
` (2 preceding siblings ...)
2026-11-06 15:11 ` [PATCH v8 3/7] drm/lease: Add a helper to tell whether a lease was revoked Maxime Ripard
@ 2026-11-06 15:11 ` Maxime Ripard
2026-11-06 15:11 ` [PATCH v8 5/7] drm/tests: atomic: Add tests for drm_atomic_commit_fill_with_defaults() Maxime Ripard
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Maxime Ripard @ 2026-11-06 15:11 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie,
Simona Vetter, Louis Chauvet, Haneen Mohammed, Melissa Wen
Cc: Daniel Stone, Harry Wentland, Jocelyn Falempe, Jonas Ådahl,
Michel Dänzer, Pekka Paalanen, Sebastian Wick, Simon Ser,
Victoria Brekenfeld, Xaver Hugl, dri-devel, linux-kernel,
Maxime Ripard
The upcoming DRM_MODE_ATOMIC_RESET flag will need to create an atomic
commit that brings the entire device back to a pristine state, as if
no configuration had ever been applied.
Create drm_atomic_commit_fill_with_defaults() which iterates over all
CRTCs, planes, connectors, and color operations in the device and
inserts a fresh default state for each one into the commit. This uses
the atomic_create_state() hooks rather than atomic_duplicate_state(),
since atomic_create_state() provides exactly this pristine state on a
per-object basis.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic.c | 355 +++++++++++++++++++++++++++++++++++++++++++
include/drm/drm_atomic.h | 2 +
2 files changed, 357 insertions(+)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 7a77051096c9..8bda2871f394 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -1650,4 +1650,359 @@ bool drm_atomic_implements_create_state(struct drm_device *dev)
EXPORT_SYMBOL(drm_atomic_implements_create_state);
+/*
+ * Returns true if the colorop state @new differs from the colorop state
+ * @old.
+ */
+static bool drm_atomic_colorop_state_changed(const struct drm_colorop_state *old,
+ const struct drm_colorop_state *new)
+{
+ return old->bypass != new->bypass ||
+ old->curve_1d_type != new->curve_1d_type ||
+ old->multiplier != new->multiplier ||
+ old->data != new->data ||
+ old->lut1d_interpolation != new->lut1d_interpolation ||
+ old->lut3d_interpolation != new->lut3d_interpolation ||
+ old->fixed_matrix_type != new->fixed_matrix_type;
+}
+
+static int drm_atomic_commit_fill_connector_with_defaults(struct drm_file *file_priv,
+ struct drm_atomic_commit *commit,
+ struct drm_connector *connector)
+{
+ struct drm_connector_state *connector_state;
+ struct drm_crtc_state *crtc_state;
+ int ret;
+
+ if (drm_lease_held(file_priv, connector->base.id)) {
+ /*
+ * The connector is part of the lease, so it gets a
+ * pristine state: every property userspace can set goes
+ * back to its default value, which leaves the connector
+ * unbound from whatever CRTC it is currently on.
+ *
+ * That CRTC still needs to be part of the commit for the
+ * helpers to update the routing, whether it is leased or
+ * not, which is what the end of this branch takes care of.
+ */
+
+ /*
+ * drm_atomic_implements_create_state() already checked
+ * this, but connectors can be hotplugged between that
+ * lockless check and the iteration here.
+ */
+ if (!connector->funcs->atomic_create_state)
+ return -EOPNOTSUPP;
+
+ connector_state = connector->funcs->atomic_create_state(connector);
+ if (IS_ERR(connector_state))
+ return PTR_ERR(connector_state);
+
+ /*
+ * best_encoder is a routing information maintained by the
+ * atomic helpers rather than a userspace property, and it
+ * is only carried over to a new state when that state is a
+ * duplicate of the current one. Since
+ * update_connector_routing() uses it to detect the commits
+ * that keep the connector routing unchanged, let's carry
+ * the encoder currently in use over so that a reset on
+ * which userspace re-applies the exact same configuration
+ * doesn't require a modeset.
+ */
+ connector_state->best_encoder = connector->state->best_encoder;
+
+ ret = drm_atomic_commit_set_connector_state(commit, connector, connector_state);
+ if (ret) {
+ connector->funcs->atomic_destroy_state(connector, connector_state);
+ return ret;
+ }
+
+ if (!connector->state->crtc)
+ return 0;
+
+ /*
+ * Make sure the CRTC the connector is currently bound to
+ * is part of the commit. The atomic helpers need that
+ * state: set_best_encoder() clears the encoder mask of
+ * that CRTC when the connector gets detached from it.
+ */
+ crtc_state = drm_atomic_get_crtc_state(commit,
+ connector->state->crtc);
+ if (IS_ERR(crtc_state))
+ return PTR_ERR(crtc_state);
+
+ /*
+ * The pristine state unbinds the connector from that
+ * CRTC, so drop it from the connector mask like
+ * drm_atomic_set_crtc_for_connector() would.
+ */
+ crtc_state->connector_mask &= ~drm_connector_mask(connector);
+ } else {
+ /*
+ * The connector isn't part of the lease so it keeps its
+ * current state. If it is bound to a leased CRTC though,
+ * that CRTC is being reset under it and comes with an
+ * empty connector mask, so
+ * drm_atomic_add_affected_connectors() won't find the
+ * connector during the check. Pull it in here so that its
+ * routing and encoder are properly handled.
+ *
+ * The leased CRTCs are all part of the commit by now. An
+ * unleased one might not be yet, but it keeps its
+ * connector mask, so the helpers will pull the connector
+ * in on their own if that CRTC ends up being changed.
+ */
+ if (!connector->state->crtc)
+ return 0;
+
+ if (!drm_atomic_get_new_crtc_state(commit,
+ connector->state->crtc))
+ return 0;
+
+ connector_state = drm_atomic_get_connector_state(commit,
+ connector);
+ if (IS_ERR(connector_state))
+ return PTR_ERR(connector_state);
+ }
+
+ return 0;
+}
+
+/**
+ * drm_atomic_commit_fill_with_defaults - populate a commit with pristine states
+ * @file_priv: DRM file the reset was requested from, or NULL
+ * @commit: atomic commit to fill
+ *
+ * Iterate over all CRTCs, planes, connectors, and color operations in
+ * the device and insert a freshly created default state for each one
+ * into @commit. The states are created through the atomic_create_state()
+ * hooks, producing the same initial state the driver starts with rather
+ * than a copy of the current hardware state.
+ *
+ * If @file_priv is a lessee, only the CRTCs, planes and connectors part
+ * of its lease are reset, and the other ones are left untouched.
+ * @file_priv is optional: if NULL, it is considered to not hold any
+ * lease, and all objects are reset.
+ *
+ * The objects that are bound to the objects being reset are still added
+ * to the commit, with their current state: the CRTC a reset plane or
+ * connector is bound to, and the connectors bound to a reset CRTC. The
+ * atomic helpers require them to be part of the commit to update the
+ * CRTC state and the routing, and they would dereference a NULL state
+ * otherwise.
+ *
+ * In the default state, all objects are disabled: CRTCs are inactive,
+ * planes are disabled, and connectors are unbound. Driver-specific
+ * properties such as color pipeline settings or max_bpc may carry
+ * non-zero defaults appropriate for basic display output.
+ *
+ * The CRTC and plane states in the commit carry color_mgmt_changed set
+ * when the reset changes the color management properties compared to the
+ * current state, so that drivers reprogram the color management
+ * hardware.
+ *
+ * The connector states keep the encoder currently in use in their
+ * best_encoder field, like a duplicated state would, so that the atomic
+ * helpers can detect the commits that don't change the connector
+ * routing.
+ *
+ * This is meant to be used with the %DRM_MODE_ATOMIC_RESET flag, which
+ * needs to bring the device back to a known baseline before applying
+ * userspace property changes on top.
+ *
+ * Returns:
+ * 0 on success, or a negative error code on failure.
+ */
+int drm_atomic_commit_fill_with_defaults(struct drm_file *file_priv,
+ struct drm_atomic_commit *commit)
+{
+ struct drm_device *dev = commit->dev;
+ struct drm_mode_config *config = &dev->mode_config;
+ struct drm_crtc *crtc;
+ struct drm_plane *plane;
+ struct drm_connector *connector;
+ struct drm_connector_list_iter conn_iter;
+ struct drm_colorop *colorop;
+ int ret;
+
+ drm_WARN_ON(dev, !commit->acquire_ctx);
+
+ /*
+ * Private objects are ignored because none have userspace
+ * properties we might want to reset. atomic_check
+ * implementations will derive or infer their private obj state
+ * from the state that will end up being committed anyway.
+ *
+ * The CRTCs are handled before the planes and connectors so that,
+ * when those pull the CRTC they are currently bound to into the
+ * commit, a leased CRTC is already there with its pristine state
+ * while an unleased one gets duplicated and keeps its current
+ * state.
+ */
+ drm_for_each_crtc(crtc, dev) {
+ struct drm_crtc_state *crtc_state;
+
+ if (!drm_lease_held(file_priv, crtc->base.id))
+ continue;
+
+ ret = drm_modeset_lock(&crtc->mutex, commit->acquire_ctx);
+ if (ret)
+ return ret;
+
+ crtc_state = crtc->funcs->atomic_create_state(crtc);
+ if (IS_ERR(crtc_state))
+ return PTR_ERR(crtc_state);
+
+ /*
+ * The userspace property handlers only set
+ * color_mgmt_changed when a property write changes the
+ * value stored in the new state. Since the pristine states
+ * we create here are already set to their default values,
+ * restoring those defaults wouldn't set the flag, and
+ * neither would leaving the properties untouched, even
+ * though the commit clears whatever LUT or CTM is
+ * currently programmed. Compare with the current state
+ * so that the drivers reprogram the color management
+ * hardware.
+ */
+ crtc_state->color_mgmt_changed =
+ crtc->state->degamma_lut != crtc_state->degamma_lut ||
+ crtc->state->ctm != crtc_state->ctm ||
+ crtc->state->gamma_lut != crtc_state->gamma_lut;
+
+ /*
+ * adjusted_mode is derived from the mode by the atomic
+ * helpers rather than set by userspace, and mode_fixup()
+ * only recomputes it when the mode or the connectors
+ * changed. A duplicated state carries it over, so nothing
+ * needs to be recomputed when nothing changes, but the
+ * pristine states we create here would be left with a
+ * zeroed adjusted_mode on a CRTC that stays enabled across
+ * the commit. Carry it over too, so that the drivers and
+ * the vblank timestamping constants keep seeing the
+ * timings currently programmed.
+ */
+ drm_mode_copy(&crtc_state->adjusted_mode,
+ &crtc->state->adjusted_mode);
+
+ drm_atomic_commit_set_crtc_state(commit, crtc, crtc_state);
+ }
+
+ drm_for_each_plane(plane, dev) {
+ struct drm_plane_state *plane_state;
+
+ if (!drm_lease_held(file_priv, plane->base.id))
+ continue;
+
+ ret = drm_modeset_lock(&plane->mutex, commit->acquire_ctx);
+ if (ret)
+ return ret;
+
+ /*
+ * Make sure the CRTC the plane is currently enabled on is
+ * part of the commit, like drm_atomic_set_crtc_for_plane()
+ * does when userspace disables a plane. The atomic helpers
+ * need the CRTC state to update planes_changed and track
+ * the commit, and would dereference a NULL CRTC state
+ * otherwise.
+ */
+ if (plane->state->crtc) {
+ struct drm_crtc_state *crtc_state;
+
+ crtc_state = drm_atomic_get_crtc_state(commit,
+ plane->state->crtc);
+ if (IS_ERR(crtc_state))
+ return PTR_ERR(crtc_state);
+
+ /*
+ * The pristine state detaches the plane from that
+ * CRTC, so drop it from the plane mask like
+ * drm_atomic_set_crtc_for_plane() would. The mask
+ * of a leased CRTC is already empty, but an
+ * unleased one got duplicated and still has the
+ * plane in it.
+ */
+ crtc_state->plane_mask &= ~drm_plane_mask(plane);
+ }
+
+ plane_state = plane->funcs->atomic_create_state(plane);
+ if (IS_ERR(plane_state))
+ return PTR_ERR(plane_state);
+
+ /*
+ * Same thing for the planes: report a color pipeline change
+ * compared to the current state.
+ */
+ plane_state->color_mgmt_changed =
+ plane->state->color_pipeline != plane_state->color_pipeline;
+
+ drm_atomic_commit_set_plane_state(commit, plane, plane_state);
+ }
+
+ drm_for_each_colorop(colorop, dev) {
+ struct drm_plane_state *plane_state;
+ struct drm_colorop_state *colorop_state;
+
+ if (!drm_lease_held(file_priv, colorop->plane->base.id))
+ continue;
+
+ ret = drm_modeset_lock(&colorop->plane->mutex, commit->acquire_ctx);
+ if (ret)
+ return ret;
+
+ colorop_state = drm_atomic_helper_colorop_create_state(colorop);
+ if (IS_ERR(colorop_state))
+ return PTR_ERR(colorop_state);
+
+ drm_atomic_commit_set_colorop_state(commit, colorop, colorop_state);
+
+ /*
+ * Report the colorop state changes on their plane state,
+ * like drm_atomic_set_property() does when userspace
+ * changes a colorop property.
+ */
+ if (drm_atomic_colorop_state_changed(colorop->state, colorop_state)) {
+ plane_state = drm_atomic_get_new_plane_state(commit,
+ colorop->plane);
+ if (plane_state)
+ plane_state->color_mgmt_changed = true;
+ }
+ }
+
+ ret = drm_modeset_lock(&config->connection_mutex, commit->acquire_ctx);
+ if (ret)
+ return ret;
+
+ drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_for_each_connector_iter(connector, &conn_iter) {
+ ret = drm_atomic_commit_fill_connector_with_defaults(file_priv, commit, connector);
+ if (ret) {
+ drm_connector_list_iter_end(&conn_iter);
+ return ret;
+ }
+ }
+ drm_connector_list_iter_end(&conn_iter);
+
+ /*
+ * drm_lease_held() is evaluated once per object and takes
+ * idr_mutex each time, so a revocation can land between two of
+ * those checks and leave the commit with pristine states for some
+ * objects and the current state for the others. Holding idr_mutex
+ * across the whole function isn't an option, since
+ * __drm_mode_object_find() takes it while the modeset locks are
+ * already held and the ordering is therefore the other way
+ * around.
+ *
+ * A lease is always revoked as a whole though, so the lease
+ * having gone empty is enough to tell that it didn't survive.
+ */
+ if (drm_lease_revoked(file_priv)) {
+ drm_dbg_atomic(dev, "Lease revoked while filling the commit\n");
+ return -ENOENT;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_atomic_commit_fill_with_defaults);
+
/**
* drm_atomic_add_encoder_bridges - add bridges attached to an encoder
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 72c3d420f40c..cac74d43a34d 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -704,4 +704,6 @@ void drm_atomic_commit_clear(struct drm_atomic_commit *state);
bool drm_atomic_implements_create_state(struct drm_device *dev);
+int drm_atomic_commit_fill_with_defaults(struct drm_file *file_priv,
+ struct drm_atomic_commit *commit);
/**
--
2.55.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v8 5/7] drm/tests: atomic: Add tests for drm_atomic_commit_fill_with_defaults()
2026-11-06 15:11 [PATCH v8 0/7] drm: Add DRM_MODE_ATOMIC_RESET flag Maxime Ripard
` (3 preceding siblings ...)
2026-11-06 15:11 ` [PATCH v8 4/7] drm/atomic: Allow filling a commit with pristine object states Maxime Ripard
@ 2026-11-06 15:11 ` Maxime Ripard
2026-11-06 15:11 ` [PATCH v8 6/7] drm/atomic-uapi: Add DRM_MODE_ATOMIC_RESET flag Maxime Ripard
2026-11-06 15:11 ` [PATCH v8 7/7] drm/vkms: Add driver-specific plane property for testing Maxime Ripard
6 siblings, 0 replies; 8+ messages in thread
From: Maxime Ripard @ 2026-11-06 15:11 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie,
Simona Vetter, Louis Chauvet, Haneen Mohammed, Melissa Wen
Cc: Daniel Stone, Harry Wentland, Jocelyn Falempe, Jonas Ådahl,
Michel Dänzer, Pekka Paalanen, Sebastian Wick, Simon Ser,
Victoria Brekenfeld, Xaver Hugl, dri-devel, linux-kernel,
Maxime Ripard, Daniel Stone
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 | 322 +++++++++++++++++++++++++++++++-
1 file changed, 320 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..f30b4c6f4259 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,323 @@ 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));
+
+ /*
+ * mode_fixup() only derives adjusted_mode when the mode or the
+ * connectors changed, so a CRTC that stays enabled across the
+ * commit must have kept the timings it was already running
+ * instead of the zeroed mode a pristine state comes with.
+ */
+ KUNIT_EXPECT_TRUE(test, drm_mode_equal(&new_crtc_state->adjusted_mode,
+ &new_crtc_state->mode));
+
+ 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
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v8 6/7] drm/atomic-uapi: Add DRM_MODE_ATOMIC_RESET flag
2026-11-06 15:11 [PATCH v8 0/7] drm: Add DRM_MODE_ATOMIC_RESET flag Maxime Ripard
` (4 preceding siblings ...)
2026-11-06 15:11 ` [PATCH v8 5/7] drm/tests: atomic: Add tests for drm_atomic_commit_fill_with_defaults() Maxime Ripard
@ 2026-11-06 15:11 ` Maxime Ripard
2026-11-06 15:11 ` [PATCH v8 7/7] drm/vkms: Add driver-specific plane property for testing Maxime Ripard
6 siblings, 0 replies; 8+ messages in thread
From: Maxime Ripard @ 2026-11-06 15:11 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie,
Simona Vetter, Louis Chauvet, Haneen Mohammed, Melissa Wen
Cc: Daniel Stone, Harry Wentland, Jocelyn Falempe, Jonas Ådahl,
Michel Dänzer, Pekka Paalanen, Sebastian Wick, Simon Ser,
Victoria Brekenfeld, Xaver Hugl, dri-devel, linux-kernel,
Maxime Ripard
From: Sebastian Wick <sebastian.wick@redhat.com>
Userspace currently has no atomic way to reset all KMS object states
to their defaults. To bring a display pipeline to a known state, a
compositor must explicitly set every property on every object, which
requires tracking which properties exist and what their defaults are.
Introduce DRM_MODE_ATOMIC_RESET (0x0800) which, when passed to the
atomic ioctl, fills the commit with default states for all KMS
objects before applying the properties supplied in the request.
Properties not explicitly included in the commit remain at their
defaults (CRTCs inactive, planes disabled, connectors unbound, and
so on).
The flag cannot be combined with DRM_MODE_PAGE_FLIP_ASYNC, since a
full state reset is incompatible with an async flip.
Since the commit contains every CRTC of the device or lease, including
the ones that are disabled before and after it, no page flip event is
attached to those: they can't report a flip, and drm_atomic_crtc_check()
would reject the whole commit. Such a CRTC doesn't count towards the
CRTCs that can signal either, so a commit that leaves them all disabled
while asking for an event is still rejected instead of waiting for an
event that would never come.
Signed-off-by: Sebastian Wick <sebastian.wick@redhat.com>
Co-developed-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic.c | 3 +++
drivers/gpu/drm/drm_atomic_uapi.c | 44 ++++++++++++++++++++++++++++++++++++---
drivers/gpu/drm/drm_ioctl.c | 5 +++++
include/uapi/drm/drm.h | 10 +++++++++
include/uapi/drm/drm_mode.h | 17 ++++++++++++++-
5 files changed, 75 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 8bda2871f394..bb5b8e527fcf 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -1614,4 +1614,7 @@ EXPORT_SYMBOL(drm_atomic_get_new_bridge_state);
* drm_atomic_helper_colorop_create_state() and do not have a per-driver hook.
*
+ * This is used to report the %DRM_CAP_ATOMIC_RESET capability to userspace,
+ * and as a precondition in drm_atomic_commit_fill_with_defaults().
+ *
* Returns:
* True if all objects implement atomic_create_state, false otherwise.
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
index 1eebcf6f5e05..77d0713c7e2d 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -1441,8 +1441,27 @@ static int prepare_signaling(struct drm_device *dev,
for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
s32 __user *fence_ptr;
+ bool page_flip_event;
fence_ptr = get_out_fence_for_crtc(crtc_state->state, crtc);
- if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT || fence_ptr) {
+ page_flip_event = arg->flags & DRM_MODE_PAGE_FLIP_EVENT;
+
+ /*
+ * A commit with the DRM_MODE_ATOMIC_RESET flag contains
+ * every CRTC of the device or lease, even the ones that are
+ * disabled before and after the commit. Those can't report
+ * a page flip, and drm_atomic_crtc_check() would reject the
+ * whole commit, so don't attach any event to them.
+ */
+ if (page_flip_event && !fence_ptr &&
+ (arg->flags & DRM_MODE_ATOMIC_RESET) &&
+ !crtc_state->active) {
+ struct drm_crtc_state *old_crtc_state;
+
+ old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
+ page_flip_event = old_crtc_state->active;
+ }
+
+ if (page_flip_event || fence_ptr) {
struct drm_pending_vblank_event *e;
@@ -1454,5 +1473,5 @@ static int prepare_signaling(struct drm_device *dev,
}
- if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
+ if (page_flip_event) {
struct drm_pending_vblank_event *e = crtc_state->event;
@@ -1495,5 +1514,6 @@ static int prepare_signaling(struct drm_device *dev,
}
- c++;
+ if (page_flip_event)
+ c++;
}
@@ -1674,4 +1694,11 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
}
+ if ((arg->flags & DRM_MODE_ATOMIC_RESET) &&
+ (arg->flags & DRM_MODE_PAGE_FLIP_ASYNC)) {
+ drm_dbg_atomic(dev,
+ "commit failed: reset cannot be combined with async flip\n");
+ return -EINVAL;
+ }
+
state = drm_atomic_commit_alloc(dev);
if (!state)
@@ -1689,4 +1716,15 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
num_fences = 0;
+ if (arg->flags & DRM_MODE_ATOMIC_RESET) {
+ if (!drm_atomic_implements_create_state(dev)) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+ ret = drm_atomic_commit_fill_with_defaults(file_priv, state);
+ if (ret)
+ goto out;
+ }
+
for (i = 0; i < arg->count_objs; i++) {
uint32_t obj_id, count_props;
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index 9039a39c4324..f666a13da6bf 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -34,4 +34,5 @@
#include <linux/uaccess.h>
+#include <drm/drm_atomic.h>
#include <drm/drm_auth.h>
#include <drm/drm_crtc.h>
@@ -305,4 +306,8 @@ static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_
dev->mode_config.async_page_flip;
break;
+ case DRM_CAP_ATOMIC_RESET:
+ req->value = drm_core_check_feature(dev, DRIVER_ATOMIC) &&
+ drm_atomic_implements_create_state(dev);
+ break;
default:
return -EINVAL;
diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
index bc7ef7684099..b6e2f2edd122 100644
--- a/include/uapi/drm/drm.h
+++ b/include/uapi/drm/drm.h
@@ -796,4 +796,14 @@ struct drm_gem_change_handle {
#define DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP 0x15
+/**
+ * DRM_CAP_ATOMIC_RESET
+ *
+ * If set to 1, the driver supports the &DRM_MODE_ATOMIC_RESET flag in
+ * &DRM_IOCTL_MODE_ATOMIC commits. When supported, userspace can pass that
+ * flag to reset all KMS object states to their defaults before applying
+ * property changes.
+ */
+#define DRM_CAP_ATOMIC_RESET 0x16
+
/* DRM_IOCTL_GET_CAP ioctl argument type */
struct drm_get_cap {
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index ed1a660a3dfd..1ab5c0fb3804 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -1329,4 +1329,18 @@ struct drm_mode_destroy_dumb {
*/
#define DRM_MODE_ATOMIC_ALLOW_MODESET 0x0400
+/**
+ * DRM_MODE_ATOMIC_RESET
+ *
+ * Reset all KMS object states (CRTCs, planes, connectors, color operations)
+ * to their default values before applying the properties in this commit.
+ * Properties not explicitly included in the commit will remain at their
+ * defaults (CRTCs inactive, planes disabled, connectors unbound, etc.).
+ *
+ * CRTCs that are disabled before and after the commit won't send any
+ * &DRM_MODE_PAGE_FLIP_EVENT.
+ *
+ * This flag cannot be combined with &DRM_MODE_PAGE_FLIP_ASYNC.
+ */
+#define DRM_MODE_ATOMIC_RESET 0x0800
/**
@@ -1341,5 +1355,6 @@ struct drm_mode_destroy_dumb {
DRM_MODE_ATOMIC_TEST_ONLY |\
DRM_MODE_ATOMIC_NONBLOCK |\
- DRM_MODE_ATOMIC_ALLOW_MODESET)
+ DRM_MODE_ATOMIC_ALLOW_MODESET |\
+ DRM_MODE_ATOMIC_RESET)
struct drm_mode_atomic {
--
2.55.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v8 7/7] drm/vkms: Add driver-specific plane property for testing
2026-11-06 15:11 [PATCH v8 0/7] drm: Add DRM_MODE_ATOMIC_RESET flag Maxime Ripard
` (5 preceding siblings ...)
2026-11-06 15:11 ` [PATCH v8 6/7] drm/atomic-uapi: Add DRM_MODE_ATOMIC_RESET flag Maxime Ripard
@ 2026-11-06 15:11 ` Maxime Ripard
6 siblings, 0 replies; 8+ messages in thread
From: Maxime Ripard @ 2026-11-06 15:11 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie,
Simona Vetter, Louis Chauvet, Haneen Mohammed, Melissa Wen
Cc: Daniel Stone, Harry Wentland, Jocelyn Falempe, Jonas Ådahl,
Michel Dänzer, Pekka Paalanen, Sebastian Wick, Simon Ser,
Victoria Brekenfeld, Xaver Hugl, dri-devel, linux-kernel,
Maxime Ripard
The DRM_MODE_ATOMIC_RESET flag allows userspace to reset all object
states to their defaults before applying new property values. Testing
that this mechanism works correctly requires a property that the test
can set to a non-default value and then verify is properly reset.
Using a standard property for this is problematic: compositors like
Mutter enumerate and track all known properties, making it difficult
to isolate the reset behavior from the compositor's own property
management.
Add a "vkms-test-do-not-use-in-prod" range property to vkms planes.
The property is stored in vkms_plane_state, duplicated across state
copies, and initialized from its registered default in
atomic_create_state via drm_object_property_get_default_value().
Reviewed-by: Daniel Stone <daniels@collabora.com>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/vkms/vkms_drv.h | 3 ++
drivers/gpu/drm/vkms/vkms_plane.c | 63 +++++++++++++++++++++++++++++++++++++--
2 files changed, 64 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
index dea6cad3f1b9..384616095b45 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.h
+++ b/drivers/gpu/drm/vkms/vkms_drv.h
@@ -147,4 +147,5 @@ struct conversion_matrix {
* struct vkms_plane_state must ensure that this pointer is valid
* @conversion_matrix: matrix used for yuv formats to convert to rgb
+ * @vkms_test_do_not_use_value: driver-specific property for testing only
*/
struct vkms_plane_state {
@@ -153,8 +154,10 @@ struct vkms_plane_state {
pixel_read_line_t pixel_read_line;
struct conversion_matrix conversion_matrix;
+ unsigned int vkms_test_do_not_use_value;
};
struct vkms_plane {
struct drm_plane base;
+ struct drm_property *vkms_test_do_not_use_property;
};
diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c
index fd3d34dcf0fe..42513cb462ac 100644
--- a/drivers/gpu/drm/vkms/vkms_plane.c
+++ b/drivers/gpu/drm/vkms/vkms_plane.c
@@ -12,8 +12,12 @@
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_print.h>
+#include <drm/drm_property.h>
#include "vkms_drv.h"
#include "vkms_formats.h"
+#define to_vkms_plane(target) \
+ container_of_const(target, struct vkms_plane, base)
+
static const u32 vkms_formats[] = {
DRM_FORMAT_ARGB8888,
@@ -55,4 +59,5 @@ static struct drm_plane_state *
vkms_plane_duplicate_state(struct drm_plane *plane)
{
+ struct vkms_plane_state *old_state = to_vkms_plane_state(plane->state);
struct vkms_plane_state *vkms_state;
@@ -61,4 +66,6 @@ vkms_plane_duplicate_state(struct drm_plane *plane)
return NULL;
+ vkms_state->vkms_test_do_not_use_value = old_state->vkms_test_do_not_use_value;
+
__drm_gem_duplicate_shadow_plane_state(plane, &vkms_state->base);
@@ -86,5 +93,7 @@ static void vkms_plane_destroy_state(struct drm_plane *plane,
static struct drm_plane_state *vkms_plane_create_state(struct drm_plane *plane)
{
+ struct vkms_plane *vkms_plane = to_vkms_plane(plane);
struct vkms_plane_state *vkms_state;
+ u64 val;
vkms_state = kzalloc_obj(*vkms_state);
@@ -96,12 +105,51 @@ static struct drm_plane_state *vkms_plane_create_state(struct drm_plane *plane)
__drm_gem_shadow_plane_state_init(plane, &vkms_state->base);
+ if (!drm_object_property_get_default_value(&plane->base,
+ vkms_plane->vkms_test_do_not_use_property,
+ &val))
+ vkms_state->vkms_test_do_not_use_value = val;
+
return &(&vkms_state->base)->base;
}
+static int vkms_plane_atomic_set_property(struct drm_plane *plane,
+ struct drm_plane_state *state,
+ struct drm_property *property,
+ uint64_t val)
+{
+ struct vkms_plane *vkms_plane = to_vkms_plane(plane);
+ struct vkms_plane_state *vkms_state = to_vkms_plane_state(state);
+
+ if (property == vkms_plane->vkms_test_do_not_use_property) {
+ vkms_state->vkms_test_do_not_use_value = val;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int vkms_plane_atomic_get_property(struct drm_plane *plane,
+ const struct drm_plane_state *state,
+ struct drm_property *property,
+ uint64_t *val)
+{
+ const struct vkms_plane_state *vkms_state = to_vkms_plane_state(state);
+ const struct vkms_plane *vkms_plane = to_vkms_plane(plane);
+
+ if (property == vkms_plane->vkms_test_do_not_use_property) {
+ *val = vkms_state->vkms_test_do_not_use_value;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
static const struct drm_plane_funcs vkms_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
- .atomic_create_state = vkms_plane_create_state,
- .atomic_duplicate_state = vkms_plane_duplicate_state,
+ .atomic_set_property = vkms_plane_atomic_set_property,
+ .atomic_get_property = vkms_plane_atomic_get_property,
+ .atomic_create_state = vkms_plane_create_state,
+ .atomic_duplicate_state = vkms_plane_duplicate_state,
.atomic_destroy_state = vkms_plane_destroy_state,
};
@@ -284,4 +332,15 @@ struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
DRM_COLOR_YCBCR_FULL_RANGE);
+ plane->vkms_test_do_not_use_property =
+ drm_property_create_range(dev, 0,
+ "vkms-test-do-not-use-in-prod",
+ 0, U32_MAX);
+ if (!plane->vkms_test_do_not_use_property)
+ return ERR_PTR(-ENOMEM);
+
+ drm_object_attach_property(&plane->base.base,
+ plane->vkms_test_do_not_use_property,
+ 0);
+
if (vkms_config_plane_get_default_pipeline(plane_cfg))
vkms_initialize_colorops(&plane->base);
--
2.55.0
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-11-06 15:12 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-06 15:11 [PATCH v8 0/7] drm: Add DRM_MODE_ATOMIC_RESET flag Maxime Ripard
2026-11-06 15:11 ` [PATCH v8 1/7] drm/amd/display: Fix planes atomic_create_state implementation Maxime Ripard
2026-11-06 15:11 ` [PATCH v8 2/7] drm/atomic: Add drm_atomic_implements_create_state() helper Maxime Ripard
2026-11-06 15:11 ` [PATCH v8 3/7] drm/lease: Add a helper to tell whether a lease was revoked Maxime Ripard
2026-11-06 15:11 ` [PATCH v8 4/7] drm/atomic: Allow filling a commit with pristine object states Maxime Ripard
2026-11-06 15:11 ` [PATCH v8 5/7] drm/tests: atomic: Add tests for drm_atomic_commit_fill_with_defaults() Maxime Ripard
2026-11-06 15:11 ` [PATCH v8 6/7] drm/atomic-uapi: Add DRM_MODE_ATOMIC_RESET flag Maxime Ripard
2026-11-06 15:11 ` [PATCH v8 7/7] drm/vkms: Add driver-specific plane property for testing Maxime Ripard
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®