* [PATCH 0/2] drm/client: Clear stale cmdline modes before the 1024x768 clone pass
@ 2026-10-31 21:56 Hugo Sales
2026-10-31 21:56 ` [PATCH 1/2] drm/client: Clear " Hugo Sales
2026-10-31 21:57 ` [PATCH 2/2] drm/tests: client-modeset: Test cloning with video= on one connector Hugo Sales
0 siblings, 2 replies; 3+ messages in thread
From: Hugo Sales @ 2026-10-31 21:56 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: David Airlie, Simona Vetter, Ville Syrjälä,
dri-devel, linux-kernel
drm_client_target_cloned() first tries to clone with the mode each
connector got from the kernel's video= option, then falls back to
1024x768 on every connector. The fallback keeps the modes the first
pass left behind, so a connector that has a video= mode set and no
1024x768 mode can make it report a clone with modes that differ. On a
single-CRTC device one connector then gets no CRTC
Patch 1 frees those modes before the fallback. Patch 2 adds a KUnit
test that fails without it
Sashiko flagged this while reviewing my fbdev probe series [1]. I
haven't hit it on hardware: it needs a single-CRTC device with two
connected outputs and video= set on only some of them, and it only shows
on the fbdev console. The KUnit test reproduces it, but how often it
happens on real systems is unconfirmed
[1] https://lore.kernel.org/all/20261024165355.2782145-1-hugo@hsal.es/
Hugo Sales (2):
drm/client: Clear cmdline modes before the 1024x768 clone pass
drm/tests: client-modeset: Test cloning with video= on one connector
drivers/gpu/drm/drm_client_modeset.c | 2 +
.../gpu/drm/tests/drm_client_modeset_test.c | 109 +++++++++++++++++-
2 files changed, 110 insertions(+), 1 deletion(-)
base-commit: a1e63ab695ad76850ab9787b9eb6aab695dc2965
--
2.56.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 1/2] drm/client: Clear cmdline modes before the 1024x768 clone pass
2026-10-31 21:56 [PATCH 0/2] drm/client: Clear stale cmdline modes before the 1024x768 clone pass Hugo Sales
@ 2026-10-31 21:56 ` Hugo Sales
2026-10-31 21:57 ` [PATCH 2/2] drm/tests: client-modeset: Test cloning with video= on one connector Hugo Sales
1 sibling, 0 replies; 3+ messages in thread
From: Hugo Sales @ 2026-10-31 21:56 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: David Airlie, Simona Vetter, Ville Syrjälä,
dri-devel, linux-kernel
drm_client_target_cloned() first tries to clone with each connector's
cmdline mode. That pass fills modes[] as it goes and stops at the first
enabled connector without a cmdline mode, or ends with modes that don't
match. Either way the earlier slots keep their cmdline modes
The 1024x768 pass that follows only writes a slot when the connector has
a matching mode, and relies on an empty slot to spot a connector it
can't clone. A connector with a mode from video= and no 1024x768 mode
keeps its cmdline mode instead, so the function returns true with modes
that differ. drm_client_target_preferred() then never runs, and on a
single-CRTC device drm_client_pick_crtcs() leaves one of the connectors
without a CRTC
Free the modes from the cmdline pass before looking for 1024x768
Fixes: 1d42bbc8f7f9 ("drm/fbdev: fix cloning on fbcon")
Signed-off-by: Hugo Sales <hugo@hsal.es>
---
Sashiko flagged this while reviewing my fbdev probe series [1]. The bug
predates that series, so I'm sending the fix on its own. I haven't hit
it on hardware. The KUnit test in the next patch fails without this fix
and passes with it
DRM KUnit on UML passes 672/672, also with KASAN and with kmemleak.
kmemleak reports six objects leaked by drm_bridge tests, which it also
reports on the base without this series
[1] https://lore.kernel.org/all/20261024165355.2782145-1-hugo@hsal.es/
---
drivers/gpu/drm/drm_client_modeset.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c
index 0080a8e9556a5..5e45beea66438 100644
--- a/drivers/gpu/drm/drm_client_modeset.c
+++ b/drivers/gpu/drm/drm_client_modeset.c
@@ -343,6 +343,8 @@ static bool drm_client_target_cloned(struct drm_device *dev,
return true;
}
+ modes_destroy(dev, modes, connector_count);
+
/* try and find a 1024x768 mode on each connector */
can_clone = true;
dmt_mode = drm_mode_find_dmt(dev, 1024, 768, 60, false);
--
2.56.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 2/2] drm/tests: client-modeset: Test cloning with video= on one connector
2026-10-31 21:56 [PATCH 0/2] drm/client: Clear stale cmdline modes before the 1024x768 clone pass Hugo Sales
2026-10-31 21:56 ` [PATCH 1/2] drm/client: Clear " Hugo Sales
@ 2026-10-31 21:57 ` Hugo Sales
1 sibling, 0 replies; 3+ messages in thread
From: Hugo Sales @ 2026-10-31 21:57 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: David Airlie, Simona Vetter, Ville Syrjälä,
dri-devel, linux-kernel
Add a drm_client_target_cloned() test with two connectors. The first
one has a video= mode and only 1920x1080, the second one has no video=
mode and only 1024x768. The connectors share no mode, so the function
must not report them as clonable
Without the previous commit the first connector keeps its cmdline mode
through the 1024x768 pass and the test fails
Signed-off-by: Hugo Sales <hugo@hsal.es>
---
.../gpu/drm/tests/drm_client_modeset_test.c | 109 +++++++++++++++++-
1 file changed, 108 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/tests/drm_client_modeset_test.c b/drivers/gpu/drm/tests/drm_client_modeset_test.c
index ec58fe064d862..a8b316fbe8433 100644
--- a/drivers/gpu/drm/tests/drm_client_modeset_test.c
+++ b/drivers/gpu/drm/tests/drm_client_modeset_test.c
@@ -10,6 +10,7 @@
#include <drm/drm_edid.h>
#include <drm/drm_drv.h>
#include <drm/drm_kunit_helpers.h>
+#include <drm/drm_managed.h>
#include <drm/drm_modes.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_probe_helper.h>
@@ -195,7 +196,113 @@ static struct kunit_suite drm_test_pick_cmdline_test_suite = {
.test_cases = drm_test_pick_cmdline_tests
};
-kunit_test_suite(drm_test_pick_cmdline_test_suite);
+static int drm_client_target_cloned_add_dmt_mode(struct drm_connector *connector,
+ int hsize, int vsize)
+{
+ struct drm_display_mode *mode;
+
+ mode = drm_mode_find_dmt(connector->dev, hsize, vsize, 60, false);
+ if (!mode)
+ return 0;
+
+ drm_mode_probed_add(connector, mode);
+
+ return 1;
+}
+
+static int drm_client_target_cloned_get_modes_1080p(struct drm_connector *connector)
+{
+ return drm_client_target_cloned_add_dmt_mode(connector, 1920, 1080);
+}
+
+static int drm_client_target_cloned_get_modes_xga(struct drm_connector *connector)
+{
+ return drm_client_target_cloned_add_dmt_mode(connector, 1024, 768);
+}
+
+static const struct drm_connector_helper_funcs drm_client_target_cloned_1080p_helper_funcs = {
+ .get_modes = drm_client_target_cloned_get_modes_1080p,
+};
+
+static const struct drm_connector_helper_funcs drm_client_target_cloned_xga_helper_funcs = {
+ .get_modes = drm_client_target_cloned_get_modes_xga,
+};
+
+/*
+ * Only the first connector has a video= mode, so the cmdline pass stops
+ * at the second one. The first connector has no 1024x768 mode, so the
+ * 1024x768 pass must not report the two connectors as clonable
+ */
+static void drm_test_target_cloned_cmdline_on_one_connector(struct kunit *test)
+{
+ struct drm_connector *connectors[2];
+ const struct drm_display_mode *modes[ARRAY_SIZE(connectors)] = {};
+ struct drm_client_offset offsets[ARRAY_SIZE(connectors)] = {};
+ bool enabled[ARRAY_SIZE(connectors)] = { true, true };
+ struct drm_device *drm;
+ struct device *dev;
+ bool cloned;
+ int i, ret;
+
+ dev = drm_kunit_helper_alloc_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+
+ drm = __drm_kunit_helper_alloc_drm_device(test, dev, sizeof(*drm), 0,
+ DRIVER_MODESET);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm);
+
+ for (i = 0; i < ARRAY_SIZE(connectors); i++) {
+ connectors[i] = drmm_kzalloc(drm, sizeof(*connectors[i]), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, connectors[i]);
+
+ ret = drmm_connector_init(drm, connectors[i],
+ &drm_client_modeset_connector_funcs,
+ DRM_MODE_CONNECTOR_Unknown, NULL);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ /* Drop any video= option the kernel was booted with */
+ memset(&connectors[i]->cmdline_mode, 0,
+ sizeof(connectors[i]->cmdline_mode));
+ connectors[i]->force = DRM_FORCE_UNSPECIFIED;
+ }
+
+ drm_connector_helper_add(connectors[0],
+ &drm_client_target_cloned_1080p_helper_funcs);
+ drm_connector_helper_add(connectors[1],
+ &drm_client_target_cloned_xga_helper_funcs);
+
+ KUNIT_ASSERT_TRUE(test,
+ drm_mode_parse_command_line_for_connector("1920x1080@60",
+ connectors[0],
+ &connectors[0]->cmdline_mode));
+
+ mutex_lock(&drm->mode_config.mutex);
+ for (i = 0; i < ARRAY_SIZE(connectors); i++) {
+ ret = drm_helper_probe_single_connector_modes(connectors[i],
+ 1920, 1080);
+ KUNIT_EXPECT_EQ(test, ret, 1);
+ }
+ cloned = drm_client_target_cloned(drm, connectors, ARRAY_SIZE(connectors),
+ modes, offsets, enabled, 1920, 1080);
+ mutex_unlock(&drm->mode_config.mutex);
+
+ KUNIT_EXPECT_FALSE(test, cloned);
+
+ modes_destroy(drm, modes, ARRAY_SIZE(connectors));
+}
+
+static struct kunit_case drm_test_target_cloned_tests[] = {
+ KUNIT_CASE(drm_test_target_cloned_cmdline_on_one_connector),
+ {}
+};
+
+static struct kunit_suite drm_test_target_cloned_test_suite = {
+ .name = "drm_test_target_cloned",
+ .test_cases = drm_test_target_cloned_tests
+};
+
+kunit_test_suites(&drm_test_pick_cmdline_test_suite,
+ &drm_test_target_cloned_test_suite);
/*
* This file is included directly by drm_client_modeset.c so we can't
--
2.56.0
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-31 21:57 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-31 21:56 [PATCH 0/2] drm/client: Clear stale cmdline modes before the 1024x768 clone pass Hugo Sales
2026-10-31 21:56 ` [PATCH 1/2] drm/client: Clear " Hugo Sales
2026-10-31 21:57 ` [PATCH 2/2] drm/tests: client-modeset: Test cloning with video= on one connector Hugo Sales
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®