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>,
"Dave Stevenson" <dave.stevenson@raspberrypi.com>,
"Maíra Canal" <mcanal@igalia.com>,
"Raspberry Pi Kernel Maintenance" <kernel-list@raspberrypi.com>
Subject: [PATCH v9 07/10] drm/vc4: Carry the HVS channel over to created CRTC states
Date: Tue, 10 Nov 2026 17:02:54 +0100 [thread overview]
Message-ID: <20261110-drm-reset-state-flag-v9-7-ddb0e26324a0@kernel.org> (raw)
In-Reply-To: <20261110-drm-reset-state-flag-v9-0-ddb0e26324a0@kernel.org>
drm_atomic_commit_fill_with_defaults() builds its commits out of
states created through atomic_create_state() instead of duplicating
the current state. A created CRTC state comes with its
assigned_channel left to VC4_HVS_CHANNEL_DISABLED, while a duplicated
state carries the channel currently in use.
vc4_pv_muxing_atomic_check() skips the CRTCs whose enablement doesn't
change, so a CRTC that stays enabled with a created state keeps its
channel unset, and vc4_core_clock_atomic_check() then indexes
hvs_new_state->fifo_state[] with VC4_HVS_CHANNEL_DISABLED (-1U), far
outside of the array.
Copy the channel of the current state over in the skip branch, like a
duplicated state would have carried it. This is a no-op for duplicated
states, which already have the channel set.
Add a KUnit test that enables an output, fills a state with defaults
and re-applies the same configuration, and checks that the CRTC kept
its channel.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
To: Dave Stevenson <dave.stevenson@raspberrypi.com>
To: Maíra Canal <mcanal@igalia.com>
Cc: Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
---
drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c | 105 +++++++++++++++++++++++++
drivers/gpu/drm/vc4/vc4_kms.c | 16 +++-
2 files changed, 119 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c b/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c
index 7a54f46acff9..c868d2cd1b3d 100644
--- a/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c
+++ b/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c
@@ -1119,14 +1119,119 @@ drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable_too_many_crtc_state(struct ku
drm_modeset_drop_locks(&ctx);
drm_modeset_acquire_fini(&ctx);
}
+/*
+ * Test that a CRTC that stays enabled with a state created through
+ * atomic_create_state(), like the ones drm_atomic_commit_fill_with_defaults()
+ * builds for a reset, keeps the HVS channel it was assigned:
+ * vc4_pv_muxing_atomic_check() skips the CRTCs whose enablement doesn't
+ * change, so their new state has to carry the channel over from the
+ * current state, the way a duplicated state would, for
+ * vc4_core_clock_atomic_check() to see a valid channel.
+ */
+static void
+drm_test_vc5_pv_muxing_bugs_created_state_keeps_channel(struct kunit *test)
+{
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_atomic_commit *state;
+ struct vc4_crtc_state *new_vc4_crtc_state;
+ struct drm_device *drm;
+ struct vc4_dev *vc4;
+ unsigned int old_channel;
+ int ret;
+
+ vc4 = vc5_mock_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+ drm = &vc4->base;
+retry_first:
+ state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+ ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_first;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = drm_atomic_check_only(state);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_first;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
+ VC4_ENCODER_TYPE_HDMI0);
+ KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
+
+ old_channel = new_vc4_crtc_state->assigned_channel;
+ KUNIT_ASSERT_NE(test, old_channel, VC4_HVS_CHANNEL_DISABLED);
+
+ /* Make the enabled state the current one */
+ ret = drm_atomic_helper_swap_state(state, false);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+retry_second:
+ state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+ /*
+ * Fill the state with defaults, like a DRM_MODE_ATOMIC_RESET
+ * commit would, then re-apply the exact same configuration.
+ */
+ 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_second;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_second;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = drm_atomic_check_only(state);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_second;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
+ VC4_ENCODER_TYPE_HDMI0);
+ KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
+
+ KUNIT_EXPECT_EQ(test, new_vc4_crtc_state->assigned_channel, old_channel);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+}
+
static struct kunit_case vc5_pv_muxing_bugs_tests[] = {
KUNIT_CASE(drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable),
KUNIT_CASE(drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable_too_many_crtc_state),
KUNIT_CASE(drm_test_vc5_pv_muxing_bugs_stable_fifo),
+ KUNIT_CASE(drm_test_vc5_pv_muxing_bugs_created_state_keeps_channel),
{}
};
static struct kunit_suite vc5_pv_muxing_bugs_test_suite = {
.name = "vc5-pv-muxing-bugs",
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
index ab551eb2da50..562f2d1f45a4 100644
--- a/drivers/gpu/drm/vc4/vc4_kms.c
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
@@ -970,15 +970,27 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev,
drm_dbg(dev, "%s: Trying to find a channel.\n", crtc->name);
/* Nothing to do here, let's skip it */
if (old_crtc_state->enable == new_crtc_state->enable) {
- if (new_crtc_state->enable)
+ /*
+ * A CRTC that stays enabled keeps its channel. A
+ * duplicated state carries it over, but a state
+ * created through atomic_create_state() comes with
+ * the channel unset, so copy it from the current
+ * state to make sure the core clock check and the
+ * commit see the channel in use.
+ */
+ if (new_crtc_state->enable) {
+ new_vc4_crtc_state->assigned_channel =
+ old_vc4_crtc_state->assigned_channel;
+
drm_dbg(dev, "%s: Already enabled, reusing channel %d.\n",
crtc->name, new_vc4_crtc_state->assigned_channel);
- else
+ } else {
drm_dbg(dev, "%s: Disabled, ignoring.\n", crtc->name);
+ }
continue;
}
/* Muxing will need to be modified, mark it as such */
--
2.56.0
next prev parent reply other threads:[~2026-11-10 16:03 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-10 16:02 [PATCH v9 00/10] drm: Add DRM_MODE_ATOMIC_RESET flag Maxime Ripard
2026-11-10 16:02 ` [PATCH v9 01/10] drm/amd/display: Fix planes atomic_create_state implementation Maxime Ripard
2026-11-10 16:02 ` [PATCH v9 02/10] drm/atomic: Add drm_atomic_implements_create_state() helper Maxime Ripard
2026-11-10 16:02 ` [PATCH v9 03/10] drm/lease: Add a helper to tell whether a lease was revoked Maxime Ripard
2026-11-10 16:02 ` [PATCH v9 04/10] drm/atomic: Allow filling a commit with pristine object states Maxime Ripard
2026-11-10 16:02 ` [PATCH v9 05/10] drm/tests: atomic: Add tests for drm_atomic_commit_fill_with_defaults() Maxime Ripard
2026-11-10 16:02 ` [PATCH v9 06/10] drm/amd/display: Take over the current stream and dc_state Maxime Ripard
2026-11-10 16:02 ` Maxime Ripard [this message]
2026-11-10 16:02 ` [PATCH v9 08/10] drm/msm/dpu1: Carry the mixers over to created CRTC states Maxime Ripard
2026-11-10 16:02 ` [PATCH v9 09/10] drm/atomic-uapi: Add DRM_MODE_ATOMIC_RESET flag Maxime Ripard
2026-11-10 16:02 ` [PATCH v9 10/10] drm/vkms: Add driver-specific plane property for testing Maxime Ripard
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=20261110-drm-reset-state-flag-v9-7-ddb0e26324a0@kernel.org \
--to=mripard@kernel.org \
--cc=airlied@gmail.com \
--cc=contact@emersion.fr \
--cc=daniels@collabora.com \
--cc=dave.stevenson@raspberrypi.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=kernel-list@raspberrypi.com \
--cc=linux-kernel@vger.kernel.org \
--cc=louis.chauvet@bootlin.com \
--cc=maarten.lankhorst@linux.intel.com \
--cc=mcanal@igalia.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 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®