Igt-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH i-g-t 0/3] add dsc-fallback test
@ 2025-01-23  7:36 Kunal Joshi
  2025-01-23  7:36 ` [PATCH i-g-t 1/3] tests/intel/kms_mst_helper: Add helper for MST-related functions Kunal Joshi
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Kunal Joshi @ 2025-01-23  7:36 UTC (permalink / raw)
  To: igt-dev; +Cc: Kunal Joshi

Add test to check we fallback to dsc when current
link params cannot accomadate bw required by
the current mode.

Kunal Joshi (3):
  tests/intel/kms_mst_helper: Add helper for MST-related functions
  tests/intel/kms_dp_linktrain_fallback: add dsc-fallback test
  HAX: Do not merge

 tests/intel-ci/fast-feedback.testlist    |   3 +-
 tests/intel-ci/xe-fast-feedback.testlist |   3 +-
 tests/intel/kms_dp_linktrain_fallback.c  | 380 +++++++++++++++++++----
 tests/meson.build                        |   3 +
 4 files changed, 319 insertions(+), 70 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH i-g-t 1/3] tests/intel/kms_mst_helper: Add helper for MST-related functions
  2025-01-23  7:36 [PATCH i-g-t 0/3] add dsc-fallback test Kunal Joshi
@ 2025-01-23  7:36 ` Kunal Joshi
  2025-01-27  7:17   ` Sharma, Swati2
  2025-01-23  7:37 ` [PATCH i-g-t 2/3] tests/intel/kms_dp_linktrain_fallback: add dsc-fallback test Kunal Joshi
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 10+ messages in thread
From: Kunal Joshi @ 2025-01-23  7:36 UTC (permalink / raw)
  To: igt-dev; +Cc: Kunal Joshi

This patch introduces kms_mst_helper.c and kms_mst_helper.h
to centralize commonly used MST-related logic.
The new function igt_find_all_mst_output_in_topology()
enumerates MST outputs that share the same root connector,
simplifying code reuse across tests needing outputs on
same MST topology. The existing MST-related code in
kms_dp_linktrain_fallback.c is updated to use the new helper,
removing duplication. Additionally, meson.build is modified
to include kms_mst_helper.c in the build process.

Signed-off-by: Kunal Joshi <kunal1.joshi@intel.com>
---
 tests/intel/kms_dp_linktrain_fallback.c | 28 ++++---------------------
 tests/meson.build                       |  1 +
 2 files changed, 5 insertions(+), 24 deletions(-)

diff --git a/tests/intel/kms_dp_linktrain_fallback.c b/tests/intel/kms_dp_linktrain_fallback.c
index a05e2015f..b10946781 100644
--- a/tests/intel/kms_dp_linktrain_fallback.c
+++ b/tests/intel/kms_dp_linktrain_fallback.c
@@ -16,6 +16,7 @@
 #include <sys/types.h>
 
 #include "igt.h"
+#include "kms_mst_helper.h"
 
 /**
  * SUBTEST: dp-fallback
@@ -47,28 +48,6 @@ typedef int (*condition_check_fn)(int drm_fd, igt_output_t *output);
 
 IGT_TEST_DESCRIPTION("Test link training fallback");
 
-static void find_mst_outputs(int drm_fd, data_t *data,
-			     igt_output_t *output,
-			     igt_output_t *mst_outputs[],
-			     int *num_mst_outputs)
-{
-	int output_root_id, root_id;
-	igt_output_t *connector_output;
-
-	output_root_id = igt_get_dp_mst_connector_id(output);
-	/*
-	 * If output is MST check all other connected output which shares
-	 * same path and fill mst_outputs and num_mst_outputs
-	 */
-	for_each_connected_output(&data->display, connector_output) {
-		if (!igt_check_output_is_dp_mst(connector_output))
-			continue;
-		root_id = igt_get_dp_mst_connector_id(connector_output);
-		if (((*num_mst_outputs) < IGT_MAX_PIPES) && root_id == output_root_id)
-			mst_outputs[(*num_mst_outputs)++] = connector_output;
-	}
-}
-
 static bool setup_mst_outputs(data_t *data, igt_output_t *mst_output[],
 			      int *output_count)
 {
@@ -83,8 +62,9 @@ static bool setup_mst_outputs(data_t *data, igt_output_t *mst_output[],
 		    traversed_mst_outputs[i] == data->output->config.connector->connector_id)
 			return false;
 
-	find_mst_outputs(data->drm_fd, data, data->output,
-			 mst_output, output_count);
+       igt_assert_f(igt_find_all_mst_output_in_topology(data->drm_fd, &data->display, data->output,
+							mst_output, output_count),
+		    "Unable to find mst outputs\n");
 
 	for (i = 0; i < *output_count; i++) {
 		output = mst_output[i];
diff --git a/tests/meson.build b/tests/meson.build
index 33dffad31..2cbd21c2a 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -367,6 +367,7 @@ extra_sources = {
 	'kms_chamelium_frames': [ join_paths ('chamelium', 'kms_chamelium_helper.c') ],
 	'kms_chamelium_hpd': [ join_paths ('chamelium', 'kms_chamelium_helper.c') ],
 	'kms_dsc': [ join_paths ('intel', 'kms_dsc_helper.c') ],
+	'kms_dp_linktrain_fallback': [join_paths ('intel', 'kms_mst_helper.c')],
 	'kms_psr2_sf':  [ join_paths ('intel', 'kms_dsc_helper.c') ],
 }
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH i-g-t 2/3] tests/intel/kms_dp_linktrain_fallback: add dsc-fallback test
  2025-01-23  7:36 [PATCH i-g-t 0/3] add dsc-fallback test Kunal Joshi
  2025-01-23  7:36 ` [PATCH i-g-t 1/3] tests/intel/kms_mst_helper: Add helper for MST-related functions Kunal Joshi
@ 2025-01-23  7:37 ` Kunal Joshi
  2025-01-23  7:37 ` [PATCH i-g-t 3/3] HAX: Do not merge Kunal Joshi
  2025-01-23  8:22 ` ✗ GitLab.Pipeline: warning for add dsc-fallback test Patchwork
  3 siblings, 0 replies; 10+ messages in thread
From: Kunal Joshi @ 2025-01-23  7:37 UTC (permalink / raw)
  To: igt-dev; +Cc: Kunal Joshi, Ankit Nautiyal

add new dsc-fallback test which finds a mode
which can be driven without DSC at current link
params and reduces link param till we have
combination (link_rate, lane_count) which requires
DSC to be enabled.

Cc: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
Signed-off-by: Kunal Joshi <kunal1.joshi@intel.com>
---
 tests/intel/kms_dp_linktrain_fallback.c | 352 +++++++++++++++++++++---
 tests/meson.build                       |   4 +-
 2 files changed, 311 insertions(+), 45 deletions(-)

diff --git a/tests/intel/kms_dp_linktrain_fallback.c b/tests/intel/kms_dp_linktrain_fallback.c
index b10946781..471381f1d 100644
--- a/tests/intel/kms_dp_linktrain_fallback.c
+++ b/tests/intel/kms_dp_linktrain_fallback.c
@@ -17,10 +17,14 @@
 
 #include "igt.h"
 #include "kms_mst_helper.h"
+#include "kms_dsc_helper.h"
 
 /**
  * SUBTEST: dp-fallback
  * Description: Test fallback on DP connectors
+ *
+ * SUBTEST: dsc-fallback
+ * Description: Test we fallback to DSC when BW isn't sufficient
  */
 
 #define RETRAIN_COUNT 1
@@ -238,16 +242,124 @@ static int check_condition_with_timeout(int drm_fd, igt_output_t *output,
 	}
 }
 
+/*
+ * Force a link training failure followed by link retrain, then
+ * block until the driver has no further pending retrain/failure.
+ * Returns false if we time out waiting.
+ */
+static bool force_failure_and_wait(data_t *data,
+				   igt_output_t *output,
+				   int failure_type,
+				   int retrain_count,
+				   double interval,
+				   double timeout)
+{
+	igt_force_lt_failure(data->drm_fd, output, failure_type);
+	igt_force_link_retrain(data->drm_fd, output, retrain_count);
+
+	/* Wait until there's no pending retrain */
+	if (check_condition_with_timeout(data->drm_fd, output,
+					 igt_get_dp_pending_retrain,
+					 interval, timeout)) {
+		igt_info("Timed out waiting for pending retrain.\n");
+		return false;
+	}
+
+	/* Wait until there's no pending LT failures */
+	if (check_condition_with_timeout(data->drm_fd, output,
+					 igt_get_dp_pending_lt_failures,
+					 interval, timeout)) {
+		igt_info("Timed out waiting for pending LT failures.\n");
+		return false;
+	}
+
+	return true;
+}
+
+/*
+ * Waits for a hotplug event, then checks that the link-status is BAD.
+ * Returns false if the link-status isn't BAD or no hotplug arrives in time.
+ */
+static bool wait_for_hotplug_and_check_bad(int drm_fd,
+					   data_t *data,
+					   igt_output_t *output,
+					   struct udev_monitor *mon,
+					   double hotplug_timeout)
+{
+	uint32_t link_status_prop_id;
+	uint64_t link_status_value;
+	drmModePropertyPtr link_status_prop;
+
+	if (!igt_hotplug_detected(mon, hotplug_timeout)) {
+		igt_info("No hotplug event within %.2f seconds.\n", hotplug_timeout);
+		return false;
+	}
+
+	kmstest_get_property(drm_fd,
+			     output->config.connector->connector_id,
+			     DRM_MODE_OBJECT_CONNECTOR,
+			     "link-status",
+			     &link_status_prop_id, &link_status_value,
+			     &link_status_prop);
+
+	if (link_status_value != DRM_MODE_LINK_STATUS_BAD) {
+		igt_info("Expected link-status=BAD but got %" PRIu64 "\n",
+			 link_status_value);
+		return false;
+	}
+
+	return true;
+}
+
+/*
+ * Sets link status=GOOD for the specified outputs, then calls
+ * validate_modeset_for_outputs() to re-commit. Returns false
+ * if the re-commit fails.
+ */
+static bool fix_link_status_and_recommit(data_t *data,
+					 igt_output_t *outputs[],
+					 int *output_count,
+					 drmModeModeInfo * modes[],
+					 struct igt_fb fbs[],
+					 struct igt_plane *primarys[])
+{
+	int i;
+	igt_output_t *out;
+
+	/* Set link-status=GOOD on each tested output */
+	for_each_connected_output(&data->display, out) {
+		for (i = 0; i < *output_count; i++) {
+			if (out->id == outputs[i]->id) {
+				igt_output_set_prop_value(
+					out, IGT_CONNECTOR_LINK_STATUS,
+					DRM_MODE_LINK_STATUS_GOOD);
+			}
+		}
+	}
+
+	if (!validate_modeset_for_outputs(data, outputs, output_count,
+					  modes, fbs, primarys)) {
+		igt_info("Modeset validation failed after forcing link-status=GOOD.\n");
+		return false;
+	}
+
+	if (igt_display_try_commit_atomic(&data->display,
+					  DRM_MODE_ATOMIC_ALLOW_MODESET,
+					  NULL) != 0) {
+		igt_info("Commit failed after restoring link-status=GOOD.\n");
+		return false;
+	}
+
+	return true;
+}
+
 static void test_fallback(data_t *data, bool is_mst)
 {
 	int output_count, retries;
 	int max_link_rate, curr_link_rate, prev_link_rate;
 	int max_lane_count, curr_lane_count, prev_lane_count;
 	igt_output_t *outputs[IGT_MAX_PIPES];
-	uint32_t link_status_prop_id;
-	uint64_t link_status_value;
-	drmModeModeInfo *modes[IGT_MAX_PIPES];
-	drmModePropertyPtr link_status_prop;
+	drmModeModeInfo * modes[IGT_MAX_PIPES];
 	struct igt_fb fbs[IGT_MAX_PIPES];
 	struct igt_plane *primarys[IGT_MAX_PIPES];
 	struct udev_monitor *mon;
@@ -256,71 +368,71 @@ static void test_fallback(data_t *data, bool is_mst)
 
 	igt_display_reset(&data->display);
 	igt_reset_link_params(data->drm_fd, data->output);
-	if (!setup_outputs(data, is_mst, outputs,
-			   &output_count, modes, fbs,
-			   primarys))
+	igt_force_link_retrain(data->drm_fd, data->output, 1);
+
+	if (!setup_outputs(data, is_mst, outputs, &output_count,
+			   modes, fbs, primarys))
 		return;
 
 	igt_info("Testing link training fallback on %s\n",
 		 igt_output_name(data->output));
 	max_link_rate = igt_get_max_link_rate(data->drm_fd, data->output);
 	max_lane_count = igt_get_max_lane_count(data->drm_fd, data->output);
+
 	prev_link_rate = igt_get_current_link_rate(data->drm_fd, data->output);
 	prev_lane_count = igt_get_current_lane_count(data->drm_fd, data->output);
 
-	while (!igt_get_dp_link_retrain_disabled(data->drm_fd,
-						 data->output)) {
+	while (!igt_get_dp_link_retrain_disabled(data->drm_fd, data->output)) {
 		igt_info("Current link rate: %d, Current lane count: %d\n",
-			 prev_link_rate,
-			 prev_lane_count);
+			 prev_link_rate, prev_lane_count);
+
 		mon = igt_watch_uevents();
-		igt_force_lt_failure(data->drm_fd, data->output,
-				     LT_FAILURE_REDUCED_CAPS);
-		igt_force_link_retrain(data->drm_fd, data->output,
-				       RETRAIN_COUNT);
-
-		igt_assert_eq(check_condition_with_timeout(data->drm_fd,
-							   data->output,
-							   igt_get_dp_pending_retrain,
-							   1.0, 20.0), 0);
-		igt_assert_eq(check_condition_with_timeout(data->drm_fd,
-							   data->output,
-							   igt_get_dp_pending_lt_failures,
-							   1.0, 20.0), 0);
+
+		/* Force link failure, wait for retrain to clear */
+		igt_assert_f(force_failure_and_wait(data, data->output,
+						    LT_FAILURE_REDUCED_CAPS,
+						    RETRAIN_COUNT,
+						    1.0, 20.0),
+			     "Link training failure steps timed out\n");
 
 		if (igt_get_dp_link_retrain_disabled(data->drm_fd,
 						     data->output)) {
 			igt_reset_connectors();
+			igt_flush_uevents(mon);
 			return;
 		}
 
-		igt_assert_f(igt_hotplug_detected(mon, 20),
-			     "Didn't get hotplug for force link training failure\n");
-
-		kmstest_get_property(data->drm_fd,
-				data->output->config.connector->connector_id,
-				DRM_MODE_OBJECT_CONNECTOR, "link-status",
-				&link_status_prop_id, &link_status_value,
-				&link_status_prop);
-		igt_assert_eq(link_status_value, DRM_MODE_LINK_STATUS_BAD);
+		/* Wait for hotplug + check link-status=BAD */
+		igt_assert_f(wait_for_hotplug_and_check_bad(data->drm_fd,
+							    data,
+							    data->output,
+							    mon,
+							    20.0),
+			     "Didn't get hotplug or link-status=BAD\n");
 		igt_flush_uevents(mon);
-		set_connector_link_status_good(data, outputs, &output_count);
-		igt_assert_f(validate_modeset_for_outputs(data,
+
+		/* Set link-status=GOOD and re-commit */
+		igt_assert_f(fix_link_status_and_recommit(data,
 							  outputs,
 							  &output_count,
 							  modes,
 							  fbs,
 							  primarys),
 			     "modeset failed\n");
-		igt_display_commit2(&data->display, COMMIT_ATOMIC);
 
-		igt_assert_eq(data->output->values[IGT_CONNECTOR_LINK_STATUS], DRM_MODE_LINK_STATUS_GOOD);
-		curr_link_rate = igt_get_current_link_rate(data->drm_fd, data->output);
-		curr_lane_count = igt_get_current_lane_count(data->drm_fd, data->output);
+		/* Ensure link-status is GOOD again */
+		igt_assert_eq(data->output->values[IGT_CONNECTOR_LINK_STATUS],
+			      DRM_MODE_LINK_STATUS_GOOD);
+
+		curr_link_rate = igt_get_current_link_rate(data->drm_fd,
+							   data->output);
+		curr_lane_count = igt_get_current_lane_count(data->drm_fd,
+							     data->output);
 
 		igt_assert_f((curr_link_rate < prev_link_rate ||
-			     curr_lane_count < prev_lane_count) ||
-			     ((curr_link_rate == max_link_rate && curr_lane_count == max_lane_count) && --retries),
+			      curr_lane_count < prev_lane_count) ||
+			     ((curr_link_rate == max_link_rate &&
+			       curr_lane_count == max_lane_count) && --retries),
 			     "Fallback unsuccessful\n");
 
 		prev_link_rate = curr_link_rate;
@@ -328,7 +440,117 @@ static void test_fallback(data_t *data, bool is_mst)
 	}
 }
 
-static bool run_test(data_t *data)
+static void test_dsc_sst_fallback(data_t *data)
+{
+	bool non_dsc_mode_found = false;
+	bool dsc_fallback_successful = false;
+	int ret;
+	struct udev_monitor *mon;
+	drmModeModeInfo *mode_to_check;
+	igt_output_t *outputs[IGT_MAX_PIPES];
+	int output_count = 0;
+
+	igt_info("Checking DSC fallback on %s\n", igt_output_name(data->output));
+	data->pipe = PIPE_A;
+
+        igt_display_reset(&data->display);
+        igt_reset_link_params(data->drm_fd, data->output);
+	igt_force_link_retrain(data->drm_fd, data->output, 1);
+
+	/* Find a mode that doesn't require DSC initially */
+	for_each_connector_mode(data->output) {
+		data->mode = &data->output->config.connector->modes[j__];
+		igt_create_color_fb(data->drm_fd, data->mode->hdisplay,
+				    data->mode->vdisplay, DRM_FORMAT_XRGB8888,
+				    DRM_FORMAT_MOD_LINEAR, 0.0, 1.0, 0.0,
+				    &data->fb);
+		igt_output_override_mode(data->output, data->mode);
+		igt_output_set_pipe(data->output, data->pipe);
+		data->primary = igt_output_get_plane_type(data->output,
+						DRM_PLANE_TYPE_PRIMARY);
+		igt_plane_set_fb(data->primary, &data->fb);
+
+		ret = igt_display_try_commit_atomic(&data->display,
+						    DRM_MODE_ATOMIC_TEST_ONLY |
+						    DRM_MODE_ATOMIC_ALLOW_MODESET,
+						    NULL);
+		if (ret != 0) {
+			igt_info("Skipping mode %dx%d@%d on %s\n",
+				 data->mode->hdisplay, data->mode->vdisplay,
+				 data->mode->vrefresh,
+				 igt_output_name(data->output));
+			continue;
+		}
+		igt_display_commit2(&data->display, COMMIT_ATOMIC);
+
+		if (!igt_is_dsc_enabled(data->drm_fd,
+					data->output->name)) {
+			drmModeModeInfo *non_dsc_mode
+				= igt_output_get_mode(data->output);
+			igt_info("Found mode %dx%d@%d %s that doesn't need DSC with link rate %d and lane count %d\n",
+				 non_dsc_mode->hdisplay, non_dsc_mode->vdisplay,
+				 non_dsc_mode->vrefresh, non_dsc_mode->name,
+				 igt_get_current_link_rate(data->drm_fd, data->output),
+				 igt_get_current_lane_count(data->drm_fd, data->output));
+			non_dsc_mode_found = true;
+			break;
+		}
+	}
+	igt_require_f(non_dsc_mode_found,
+		      "No non-DSC mode found on %s\n",
+		      igt_output_name(data->output));
+
+
+	/* Repeatedly force link failure until DSC is required (or link is disabled) */
+	while (!igt_get_dp_link_retrain_disabled(data->drm_fd, data->output)) {
+		mon = igt_watch_uevents();
+
+		igt_assert_f(force_failure_and_wait(data, data->output,
+						    LT_FAILURE_REDUCED_CAPS,
+						    RETRAIN_COUNT, 1.0, 20.0),
+			     "Forcing DSC fallback timed out\n");
+
+		if (igt_get_dp_link_retrain_disabled(data->drm_fd,
+						     data->output)) {
+			igt_reset_connectors();
+			igt_flush_uevents(mon);
+			return;
+		}
+
+		igt_assert_f(wait_for_hotplug_and_check_bad(data->drm_fd,
+							    data,
+							    data->output,
+							    mon,
+							    20.0),
+			     "Didn't get hotplug or link-status=BAD for DSC\n");
+		igt_flush_uevents(mon);
+
+		outputs[output_count++] = data->output;
+		set_connector_link_status_good(data, outputs, &output_count);
+		igt_display_commit2(&data->display, COMMIT_ATOMIC);
+
+		mode_to_check = igt_output_get_mode(data->output);
+
+		if (igt_is_dsc_enabled(data->drm_fd, data->output->name)) {
+			igt_info("mode %dx%d@%d now requires DSC with link rate %d and lane count %d\n",
+				 mode_to_check->hdisplay, mode_to_check->vdisplay,
+				 mode_to_check->vrefresh,
+				 igt_get_current_link_rate(data->drm_fd, data->output),
+				 igt_get_current_lane_count(data->drm_fd, data->output));
+			igt_info("DSC fallback successful on %s\n",
+				 igt_output_name(data->output));
+			dsc_fallback_successful = true;
+			break;
+		} else {
+			igt_info("mode %dx%d@%d still doesn't require DSC\n",
+				 mode_to_check->hdisplay, mode_to_check->vdisplay,
+				 mode_to_check->vrefresh);
+		}
+	}
+	igt_assert_f(dsc_fallback_successful, "DSC fallback unsuccessful\n");
+}
+
+static bool run_lt_fallback_test(data_t *data)
 {
 	bool ran = false;
 	igt_output_t *output;
@@ -366,6 +588,43 @@ static bool run_test(data_t *data)
 	return ran;
 }
 
+static bool run_dsc_sst_fallaback_test(data_t *data)
+{
+	bool ran = false;
+	igt_output_t *output;
+
+	if (!is_dsc_supported_by_source(data->drm_fd)) {
+		igt_info("DSC not supported by source.\n");
+		return ran;
+	}
+
+	for_each_connected_output(&data->display, output) {
+		data->output = output;
+
+		if (!igt_has_force_link_training_failure_debugfs(data->drm_fd,
+								 data->output)) {
+			igt_info("Output %s doesn't support forcing link training.\n",
+				 igt_output_name(data->output));
+			continue;
+		}
+
+		if (output->config.connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) {
+			igt_info("Skipping output %s as it's not DP\n", output->name);
+			continue;
+		}
+
+		if (!is_dsc_supported_by_sink(data->drm_fd, data->output)) {
+			igt_info("Skipping output %s as DSC not supported by sink\n",
+				 igt_output_name(data->output));
+			continue;
+		}
+
+		ran = true;
+		test_dsc_sst_fallback(data);
+	}
+	return ran;
+}
+
 igt_main
 {
 	data_t data = {};
@@ -381,8 +640,13 @@ igt_main
 	}
 
 	igt_subtest("dp-fallback") {
-		igt_require_f(run_test(&data),
-			      "Skipping test as no output found or none supports fallback\n");
+		igt_require_f(run_lt_fallback_test(&data),
+			      "Skipping test as no DP output found or none supports forcing link fail\n");
+	}
+
+	igt_subtest("dsc-fallback") {
+		igt_require_f(run_dsc_sst_fallaback_test(&data),
+			      "Skipping test: DSC fallback conditions not met.\n");
 	}
 
 	igt_fixture {
diff --git a/tests/meson.build b/tests/meson.build
index 2cbd21c2a..dd75976dd 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -367,7 +367,9 @@ extra_sources = {
 	'kms_chamelium_frames': [ join_paths ('chamelium', 'kms_chamelium_helper.c') ],
 	'kms_chamelium_hpd': [ join_paths ('chamelium', 'kms_chamelium_helper.c') ],
 	'kms_dsc': [ join_paths ('intel', 'kms_dsc_helper.c') ],
-	'kms_dp_linktrain_fallback': [join_paths ('intel', 'kms_mst_helper.c')],
+	'kms_dp_linktrain_fallback': [
+           join_paths ('intel', 'kms_mst_helper.c'),
+           join_paths ('intel', 'kms_dsc_helper.c')],
 	'kms_psr2_sf':  [ join_paths ('intel', 'kms_dsc_helper.c') ],
 }
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH i-g-t 3/3] HAX: Do not merge
  2025-01-23  7:36 [PATCH i-g-t 0/3] add dsc-fallback test Kunal Joshi
  2025-01-23  7:36 ` [PATCH i-g-t 1/3] tests/intel/kms_mst_helper: Add helper for MST-related functions Kunal Joshi
  2025-01-23  7:37 ` [PATCH i-g-t 2/3] tests/intel/kms_dp_linktrain_fallback: add dsc-fallback test Kunal Joshi
@ 2025-01-23  7:37 ` Kunal Joshi
  2025-01-23  8:22 ` ✗ GitLab.Pipeline: warning for add dsc-fallback test Patchwork
  3 siblings, 0 replies; 10+ messages in thread
From: Kunal Joshi @ 2025-01-23  7:37 UTC (permalink / raw)
  To: igt-dev; +Cc: Kunal Joshi

Don't merge, just for CI testing
---
 tests/intel-ci/fast-feedback.testlist    | 3 ++-
 tests/intel-ci/xe-fast-feedback.testlist | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/tests/intel-ci/fast-feedback.testlist b/tests/intel-ci/fast-feedback.testlist
index be0965110..668fb3888 100644
--- a/tests/intel-ci/fast-feedback.testlist
+++ b/tests/intel-ci/fast-feedback.testlist
@@ -1,6 +1,7 @@
 # Try to load the driver if it's not available yet.
 igt@i915_module_load@load
-
+igt@kms_dp_linktrain_fallback@dsc-fallback
+igt@kms_dp_linktrain_fallback@dp-fallbck
 # Keep alphabetically sorted by default
 igt@core_auth@basic-auth
 igt@debugfs_test@read_all_entries
diff --git a/tests/intel-ci/xe-fast-feedback.testlist b/tests/intel-ci/xe-fast-feedback.testlist
index 0234d3e72..28f8b5015 100644
--- a/tests/intel-ci/xe-fast-feedback.testlist
+++ b/tests/intel-ci/xe-fast-feedback.testlist
@@ -1,6 +1,7 @@
 # Should be the first test
 igt@xe_module_load@load
-
+igt@kms_dp_linktrain_fallback@dsc-fallback
+igt@kms_dp_linktrain_fallback@dp-fallback
 igt@fbdev@eof
 igt@fbdev@info
 igt@fbdev@nullptr
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* ✗ GitLab.Pipeline: warning for add dsc-fallback test
  2025-01-23  7:36 [PATCH i-g-t 0/3] add dsc-fallback test Kunal Joshi
                   ` (2 preceding siblings ...)
  2025-01-23  7:37 ` [PATCH i-g-t 3/3] HAX: Do not merge Kunal Joshi
@ 2025-01-23  8:22 ` Patchwork
  3 siblings, 0 replies; 10+ messages in thread
From: Patchwork @ 2025-01-23  8:22 UTC (permalink / raw)
  To: Kunal Joshi; +Cc: igt-dev

== Series Details ==

Series: add dsc-fallback test
URL   : https://patchwork.freedesktop.org/series/143877/
State : warning

== Summary ==

Pipeline status: FAILED.

see https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/pipelines/1350699 for the overview.

build:tests-debian-meson has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/69822699):
  Checking whether type "struct sysinfo" has member "totalram" : YES
  Checking for function "memfd_create" : YES
  Configuring config.h using configuration
  Program python3 found: YES (/usr/bin/python3)
  Program igt_doc.py found: YES (/builds/gfx-ci/igt-ci-tags/scripts/igt_doc.py)
  Program gen_rst_index skipped: feature sphinx disabled
  Program generate_iga64_codes found: YES (/builds/gfx-ci/igt-ci-tags/scripts/generate_iga64_codes)
  lib/meson.build:172: WARNING: libdrm <= 2.4.99 found, amdgpu_cs_query_reset_state2 not applicable
  Configuring i915-perf.pc using configuration
  Configuring xe-oa.pc using configuration
  
  tests/meson.build:426:1: ERROR:  File intel/kms_mst_helper.c does not exist.
  
  A full log can be found at /builds/gfx-ci/igt-ci-tags/build/meson-logs/meson-log.txt
  section_end:1737620016:step_script
  section_start:1737620016:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1737620017:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-debian-meson-arm64 has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/69822702):
  Checking whether type "struct sysinfo" has member "totalram" : YES
  Checking for function "memfd_create" : YES
  Configuring config.h using configuration
  Program python3 found: YES (/usr/bin/python3)
  Program igt_doc.py found: YES (/builds/gfx-ci/igt-ci-tags/scripts/igt_doc.py)
  Program gen_rst_index skipped: feature sphinx disabled
  Program generate_iga64_codes found: YES (/builds/gfx-ci/igt-ci-tags/scripts/generate_iga64_codes)
  lib/meson.build:172: WARNING: libdrm <= 2.4.99 found, amdgpu_cs_query_reset_state2 not applicable
  Configuring i915-perf.pc using configuration
  Configuring xe-oa.pc using configuration
  
  tests/meson.build:426:1: ERROR:  File intel/kms_mst_helper.c does not exist.
  
  A full log can be found at /builds/gfx-ci/igt-ci-tags/build/meson-logs/meson-log.txt
  section_end:1737620016:step_script
  section_start:1737620016:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1737620016:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-debian-meson-armhf has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/69822701):
  Checking whether type "struct sysinfo" has member "totalram" : YES
  Checking for function "memfd_create" : YES
  Configuring config.h using configuration
  Program python3 found: YES (/usr/bin/python3)
  Program igt_doc.py found: YES (/builds/gfx-ci/igt-ci-tags/scripts/igt_doc.py)
  Program gen_rst_index skipped: feature sphinx disabled
  Program generate_iga64_codes found: YES (/builds/gfx-ci/igt-ci-tags/scripts/generate_iga64_codes)
  lib/meson.build:172: WARNING: libdrm <= 2.4.99 found, amdgpu_cs_query_reset_state2 not applicable
  Configuring i915-perf.pc using configuration
  Configuring xe-oa.pc using configuration
  
  tests/meson.build:426:1: ERROR:  File intel/kms_mst_helper.c does not exist.
  
  A full log can be found at /builds/gfx-ci/igt-ci-tags/build/meson-logs/meson-log.txt
  section_end:1737620033:step_script
  section_start:1737620033:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1737620034:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-debian-meson-mips has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/69822703):
  Checking whether type "struct sysinfo" has member "totalram" : YES
  Checking for function "memfd_create" : YES
  Configuring config.h using configuration
  Program python3 found: YES (/usr/bin/python3)
  Program igt_doc.py found: YES (/builds/gfx-ci/igt-ci-tags/scripts/igt_doc.py)
  Program gen_rst_index skipped: feature sphinx disabled
  Program generate_iga64_codes found: YES (/builds/gfx-ci/igt-ci-tags/scripts/generate_iga64_codes)
  lib/meson.build:172: WARNING: libdrm <= 2.4.99 found, amdgpu_cs_query_reset_state2 not applicable
  Configuring i915-perf.pc using configuration
  Configuring xe-oa.pc using configuration
  
  tests/meson.build:426:1: ERROR:  File intel/kms_mst_helper.c does not exist.
  
  A full log can be found at /builds/gfx-ci/igt-ci-tags/build/meson-logs/meson-log.txt
  section_end:1737620040:step_script
  section_start:1737620040:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1737620040:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-fedora has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/69822694):
  Header <unistd.h> has symbol "gettid" : YES 
  Checking whether type "struct sysinfo" has member "totalram" : YES 
  Checking for function "memfd_create" : YES 
  Configuring config.h using configuration
  Program python3 found: YES (/usr/bin/python3)
  Program igt_doc.py found: YES (/builds/gfx-ci/igt-ci-tags/scripts/igt_doc.py)
  Program gen_rst_index skipped: feature sphinx disabled
  Program generate_iga64_codes found: YES (/builds/gfx-ci/igt-ci-tags/scripts/generate_iga64_codes)
  Configuring i915-perf.pc using configuration
  Configuring xe-oa.pc using configuration
  
  tests/meson.build:426:1: ERROR: File intel/kms_mst_helper.c does not exist.
  
  A full log can be found at /builds/gfx-ci/igt-ci-tags/build/meson-logs/meson-log.txt
  section_end:1737620042:step_script
  section_start:1737620042:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1737620043:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-fedora-clang has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/69822698):
  Header <unistd.h> has symbol "gettid" : YES 
  Checking whether type "struct sysinfo" has member "totalram" : YES 
  Checking for function "memfd_create" : YES 
  Configuring config.h using configuration
  Program python3 found: YES (/usr/bin/python3)
  Program igt_doc.py found: YES (/builds/gfx-ci/igt-ci-tags/scripts/igt_doc.py)
  Program gen_rst_index skipped: feature sphinx disabled
  Program generate_iga64_codes found: YES (/builds/gfx-ci/igt-ci-tags/scripts/generate_iga64_codes)
  Configuring i915-perf.pc using configuration
  Configuring xe-oa.pc using configuration
  
  tests/meson.build:426:1: ERROR: File intel/kms_mst_helper.c does not exist.
  
  A full log can be found at /builds/gfx-ci/igt-ci-tags/build/meson-logs/meson-log.txt
  section_end:1737620013:step_script
  section_start:1737620013:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1737620014:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-fedora-no-libdrm-nouveau has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/69822697):
  Header <unistd.h> has symbol "gettid" : YES 
  Checking whether type "struct sysinfo" has member "totalram" : YES 
  Checking for function "memfd_create" : YES 
  Configuring config.h using configuration
  Program python3 found: YES (/usr/bin/python3)
  Program igt_doc.py found: YES (/builds/gfx-ci/igt-ci-tags/scripts/igt_doc.py)
  Program gen_rst_index skipped: feature sphinx disabled
  Program generate_iga64_codes found: YES (/builds/gfx-ci/igt-ci-tags/scripts/generate_iga64_codes)
  Configuring i915-perf.pc using configuration
  Configuring xe-oa.pc using configuration
  
  tests/meson.build:426:1: ERROR: File intel/kms_mst_helper.c does not exist.
  
  A full log can be found at /builds/gfx-ci/igt-ci-tags/build/meson-logs/meson-log.txt
  section_end:1737620027:step_script
  section_start:1737620027:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1737620027:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-fedora-no-libunwind has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/69822695):
  Header <unistd.h> has symbol "gettid" : YES 
  Checking whether type "struct sysinfo" has member "totalram" : YES 
  Checking for function "memfd_create" : YES 
  Configuring config.h using configuration
  Program python3 found: YES (/usr/bin/python3)
  Program igt_doc.py found: YES (/builds/gfx-ci/igt-ci-tags/scripts/igt_doc.py)
  Program gen_rst_index skipped: feature sphinx disabled
  Program generate_iga64_codes found: YES (/builds/gfx-ci/igt-ci-tags/scripts/generate_iga64_codes)
  Configuring i915-perf.pc using configuration
  Configuring xe-oa.pc using configuration
  
  tests/meson.build:426:1: ERROR: File intel/kms_mst_helper.c does not exist.
  
  A full log can be found at /builds/gfx-ci/igt-ci-tags/build/meson-logs/meson-log.txt
  section_end:1737620036:step_script
  section_start:1737620036:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1737620036:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

build:tests-fedora-oldest-meson has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/69822696):
  Header <unistd.h> has symbol "gettid": YES
  Checking whether type "struct sysinfo" has member "totalram" : YES
  Checking for function "memfd_create" : YES
  Configuring config.h using configuration
  Program python3 found: YES (/usr/bin/python3)
  Program igt_doc.py found: YES (/builds/gfx-ci/igt-ci-tags/scripts/igt_doc.py)
  Program gen_rst_index skipped: feature sphinx disabled
  Program generate_iga64_codes found: YES (/builds/gfx-ci/igt-ci-tags/scripts/generate_iga64_codes)
  Configuring i915-perf.pc using configuration
  Configuring xe-oa.pc using configuration
  
  tests/meson.build:426:1: ERROR:  File intel/kms_mst_helper.c does not exist.
  
  A full log can be found at /builds/gfx-ci/igt-ci-tags/build/meson-logs/meson-log.txt
  section_end:1737620044:step_script
  section_start:1737620044:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1737620045:cleanup_file_variables
  ERROR: Job failed: exit code 1

== Logs ==

For more details see: https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/pipelines/1350699

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH i-g-t 2/3] tests/intel/kms_dp_linktrain_fallback: add dsc-fallback test
  2025-01-27  6:29 [PATCH i-g-t 0/3] " Kunal Joshi
@ 2025-01-27  6:29 ` Kunal Joshi
  2025-01-27  9:17   ` Sharma, Swati2
  2025-02-10  9:56   ` Nautiyal, Ankit K
  0 siblings, 2 replies; 10+ messages in thread
From: Kunal Joshi @ 2025-01-27  6:29 UTC (permalink / raw)
  To: igt-dev; +Cc: Kunal Joshi, Ankit Nautiyal

add new dsc-fallback test which finds a mode
which can be driven without DSC at current link
params and reduces link param till we have
combination (link_rate, lane_count) which requires
DSC to be enabled.

Cc: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
Signed-off-by: Kunal Joshi <kunal1.joshi@intel.com>
---
 tests/intel/kms_dp_linktrain_fallback.c | 352 +++++++++++++++++++++---
 tests/meson.build                       |   4 +-
 2 files changed, 311 insertions(+), 45 deletions(-)

diff --git a/tests/intel/kms_dp_linktrain_fallback.c b/tests/intel/kms_dp_linktrain_fallback.c
index b10946781..471381f1d 100644
--- a/tests/intel/kms_dp_linktrain_fallback.c
+++ b/tests/intel/kms_dp_linktrain_fallback.c
@@ -17,10 +17,14 @@
 
 #include "igt.h"
 #include "kms_mst_helper.h"
+#include "kms_dsc_helper.h"
 
 /**
  * SUBTEST: dp-fallback
  * Description: Test fallback on DP connectors
+ *
+ * SUBTEST: dsc-fallback
+ * Description: Test we fallback to DSC when BW isn't sufficient
  */
 
 #define RETRAIN_COUNT 1
@@ -238,16 +242,124 @@ static int check_condition_with_timeout(int drm_fd, igt_output_t *output,
 	}
 }
 
+/*
+ * Force a link training failure followed by link retrain, then
+ * block until the driver has no further pending retrain/failure.
+ * Returns false if we time out waiting.
+ */
+static bool force_failure_and_wait(data_t *data,
+				   igt_output_t *output,
+				   int failure_type,
+				   int retrain_count,
+				   double interval,
+				   double timeout)
+{
+	igt_force_lt_failure(data->drm_fd, output, failure_type);
+	igt_force_link_retrain(data->drm_fd, output, retrain_count);
+
+	/* Wait until there's no pending retrain */
+	if (check_condition_with_timeout(data->drm_fd, output,
+					 igt_get_dp_pending_retrain,
+					 interval, timeout)) {
+		igt_info("Timed out waiting for pending retrain.\n");
+		return false;
+	}
+
+	/* Wait until there's no pending LT failures */
+	if (check_condition_with_timeout(data->drm_fd, output,
+					 igt_get_dp_pending_lt_failures,
+					 interval, timeout)) {
+		igt_info("Timed out waiting for pending LT failures.\n");
+		return false;
+	}
+
+	return true;
+}
+
+/*
+ * Waits for a hotplug event, then checks that the link-status is BAD.
+ * Returns false if the link-status isn't BAD or no hotplug arrives in time.
+ */
+static bool wait_for_hotplug_and_check_bad(int drm_fd,
+					   data_t *data,
+					   igt_output_t *output,
+					   struct udev_monitor *mon,
+					   double hotplug_timeout)
+{
+	uint32_t link_status_prop_id;
+	uint64_t link_status_value;
+	drmModePropertyPtr link_status_prop;
+
+	if (!igt_hotplug_detected(mon, hotplug_timeout)) {
+		igt_info("No hotplug event within %.2f seconds.\n", hotplug_timeout);
+		return false;
+	}
+
+	kmstest_get_property(drm_fd,
+			     output->config.connector->connector_id,
+			     DRM_MODE_OBJECT_CONNECTOR,
+			     "link-status",
+			     &link_status_prop_id, &link_status_value,
+			     &link_status_prop);
+
+	if (link_status_value != DRM_MODE_LINK_STATUS_BAD) {
+		igt_info("Expected link-status=BAD but got %" PRIu64 "\n",
+			 link_status_value);
+		return false;
+	}
+
+	return true;
+}
+
+/*
+ * Sets link status=GOOD for the specified outputs, then calls
+ * validate_modeset_for_outputs() to re-commit. Returns false
+ * if the re-commit fails.
+ */
+static bool fix_link_status_and_recommit(data_t *data,
+					 igt_output_t *outputs[],
+					 int *output_count,
+					 drmModeModeInfo * modes[],
+					 struct igt_fb fbs[],
+					 struct igt_plane *primarys[])
+{
+	int i;
+	igt_output_t *out;
+
+	/* Set link-status=GOOD on each tested output */
+	for_each_connected_output(&data->display, out) {
+		for (i = 0; i < *output_count; i++) {
+			if (out->id == outputs[i]->id) {
+				igt_output_set_prop_value(
+					out, IGT_CONNECTOR_LINK_STATUS,
+					DRM_MODE_LINK_STATUS_GOOD);
+			}
+		}
+	}
+
+	if (!validate_modeset_for_outputs(data, outputs, output_count,
+					  modes, fbs, primarys)) {
+		igt_info("Modeset validation failed after forcing link-status=GOOD.\n");
+		return false;
+	}
+
+	if (igt_display_try_commit_atomic(&data->display,
+					  DRM_MODE_ATOMIC_ALLOW_MODESET,
+					  NULL) != 0) {
+		igt_info("Commit failed after restoring link-status=GOOD.\n");
+		return false;
+	}
+
+	return true;
+}
+
 static void test_fallback(data_t *data, bool is_mst)
 {
 	int output_count, retries;
 	int max_link_rate, curr_link_rate, prev_link_rate;
 	int max_lane_count, curr_lane_count, prev_lane_count;
 	igt_output_t *outputs[IGT_MAX_PIPES];
-	uint32_t link_status_prop_id;
-	uint64_t link_status_value;
-	drmModeModeInfo *modes[IGT_MAX_PIPES];
-	drmModePropertyPtr link_status_prop;
+	drmModeModeInfo * modes[IGT_MAX_PIPES];
 	struct igt_fb fbs[IGT_MAX_PIPES];
 	struct igt_plane *primarys[IGT_MAX_PIPES];
 	struct udev_monitor *mon;
@@ -256,71 +368,71 @@ static void test_fallback(data_t *data, bool is_mst)
 
 	igt_display_reset(&data->display);
 	igt_reset_link_params(data->drm_fd, data->output);
-	if (!setup_outputs(data, is_mst, outputs,
-			   &output_count, modes, fbs,
-			   primarys))
+	igt_force_link_retrain(data->drm_fd, data->output, 1);
+
+	if (!setup_outputs(data, is_mst, outputs, &output_count,
+			   modes, fbs, primarys))
 		return;
 
 	igt_info("Testing link training fallback on %s\n",
 		 igt_output_name(data->output));
 	max_link_rate = igt_get_max_link_rate(data->drm_fd, data->output);
 	max_lane_count = igt_get_max_lane_count(data->drm_fd, data->output);
+
 	prev_link_rate = igt_get_current_link_rate(data->drm_fd, data->output);
 	prev_lane_count = igt_get_current_lane_count(data->drm_fd, data->output);
 
-	while (!igt_get_dp_link_retrain_disabled(data->drm_fd,
-						 data->output)) {
+	while (!igt_get_dp_link_retrain_disabled(data->drm_fd, data->output)) {
 		igt_info("Current link rate: %d, Current lane count: %d\n",
-			 prev_link_rate,
-			 prev_lane_count);
+			 prev_link_rate, prev_lane_count);
+
 		mon = igt_watch_uevents();
-		igt_force_lt_failure(data->drm_fd, data->output,
-				     LT_FAILURE_REDUCED_CAPS);
-		igt_force_link_retrain(data->drm_fd, data->output,
-				       RETRAIN_COUNT);
-
-		igt_assert_eq(check_condition_with_timeout(data->drm_fd,
-							   data->output,
-							   igt_get_dp_pending_retrain,
-							   1.0, 20.0), 0);
-		igt_assert_eq(check_condition_with_timeout(data->drm_fd,
-							   data->output,
-							   igt_get_dp_pending_lt_failures,
-							   1.0, 20.0), 0);
+
+		/* Force link failure, wait for retrain to clear */
+		igt_assert_f(force_failure_and_wait(data, data->output,
+						    LT_FAILURE_REDUCED_CAPS,
+						    RETRAIN_COUNT,
+						    1.0, 20.0),
+			     "Link training failure steps timed out\n");
 
 		if (igt_get_dp_link_retrain_disabled(data->drm_fd,
 						     data->output)) {
 			igt_reset_connectors();
+			igt_flush_uevents(mon);
 			return;
 		}
 
-		igt_assert_f(igt_hotplug_detected(mon, 20),
-			     "Didn't get hotplug for force link training failure\n");
-
-		kmstest_get_property(data->drm_fd,
-				data->output->config.connector->connector_id,
-				DRM_MODE_OBJECT_CONNECTOR, "link-status",
-				&link_status_prop_id, &link_status_value,
-				&link_status_prop);
-		igt_assert_eq(link_status_value, DRM_MODE_LINK_STATUS_BAD);
+		/* Wait for hotplug + check link-status=BAD */
+		igt_assert_f(wait_for_hotplug_and_check_bad(data->drm_fd,
+							    data,
+							    data->output,
+							    mon,
+							    20.0),
+			     "Didn't get hotplug or link-status=BAD\n");
 		igt_flush_uevents(mon);
-		set_connector_link_status_good(data, outputs, &output_count);
-		igt_assert_f(validate_modeset_for_outputs(data,
+
+		/* Set link-status=GOOD and re-commit */
+		igt_assert_f(fix_link_status_and_recommit(data,
 							  outputs,
 							  &output_count,
 							  modes,
 							  fbs,
 							  primarys),
 			     "modeset failed\n");
-		igt_display_commit2(&data->display, COMMIT_ATOMIC);
 
-		igt_assert_eq(data->output->values[IGT_CONNECTOR_LINK_STATUS], DRM_MODE_LINK_STATUS_GOOD);
-		curr_link_rate = igt_get_current_link_rate(data->drm_fd, data->output);
-		curr_lane_count = igt_get_current_lane_count(data->drm_fd, data->output);
+		/* Ensure link-status is GOOD again */
+		igt_assert_eq(data->output->values[IGT_CONNECTOR_LINK_STATUS],
+			      DRM_MODE_LINK_STATUS_GOOD);
+
+		curr_link_rate = igt_get_current_link_rate(data->drm_fd,
+							   data->output);
+		curr_lane_count = igt_get_current_lane_count(data->drm_fd,
+							     data->output);
 
 		igt_assert_f((curr_link_rate < prev_link_rate ||
-			     curr_lane_count < prev_lane_count) ||
-			     ((curr_link_rate == max_link_rate && curr_lane_count == max_lane_count) && --retries),
+			      curr_lane_count < prev_lane_count) ||
+			     ((curr_link_rate == max_link_rate &&
+			       curr_lane_count == max_lane_count) && --retries),
 			     "Fallback unsuccessful\n");
 
 		prev_link_rate = curr_link_rate;
@@ -328,7 +440,117 @@ static void test_fallback(data_t *data, bool is_mst)
 	}
 }
 
-static bool run_test(data_t *data)
+static void test_dsc_sst_fallback(data_t *data)
+{
+	bool non_dsc_mode_found = false;
+	bool dsc_fallback_successful = false;
+	int ret;
+	struct udev_monitor *mon;
+	drmModeModeInfo *mode_to_check;
+	igt_output_t *outputs[IGT_MAX_PIPES];
+	int output_count = 0;
+
+	igt_info("Checking DSC fallback on %s\n", igt_output_name(data->output));
+	data->pipe = PIPE_A;
+
+        igt_display_reset(&data->display);
+        igt_reset_link_params(data->drm_fd, data->output);
+	igt_force_link_retrain(data->drm_fd, data->output, 1);
+
+	/* Find a mode that doesn't require DSC initially */
+	for_each_connector_mode(data->output) {
+		data->mode = &data->output->config.connector->modes[j__];
+		igt_create_color_fb(data->drm_fd, data->mode->hdisplay,
+				    data->mode->vdisplay, DRM_FORMAT_XRGB8888,
+				    DRM_FORMAT_MOD_LINEAR, 0.0, 1.0, 0.0,
+				    &data->fb);
+		igt_output_override_mode(data->output, data->mode);
+		igt_output_set_pipe(data->output, data->pipe);
+		data->primary = igt_output_get_plane_type(data->output,
+						DRM_PLANE_TYPE_PRIMARY);
+		igt_plane_set_fb(data->primary, &data->fb);
+
+		ret = igt_display_try_commit_atomic(&data->display,
+						    DRM_MODE_ATOMIC_TEST_ONLY |
+						    DRM_MODE_ATOMIC_ALLOW_MODESET,
+						    NULL);
+		if (ret != 0) {
+			igt_info("Skipping mode %dx%d@%d on %s\n",
+				 data->mode->hdisplay, data->mode->vdisplay,
+				 data->mode->vrefresh,
+				 igt_output_name(data->output));
+			continue;
+		}
+		igt_display_commit2(&data->display, COMMIT_ATOMIC);
+
+		if (!igt_is_dsc_enabled(data->drm_fd,
+					data->output->name)) {
+			drmModeModeInfo *non_dsc_mode
+				= igt_output_get_mode(data->output);
+			igt_info("Found mode %dx%d@%d %s that doesn't need DSC with link rate %d and lane count %d\n",
+				 non_dsc_mode->hdisplay, non_dsc_mode->vdisplay,
+				 non_dsc_mode->vrefresh, non_dsc_mode->name,
+				 igt_get_current_link_rate(data->drm_fd, data->output),
+				 igt_get_current_lane_count(data->drm_fd, data->output));
+			non_dsc_mode_found = true;
+			break;
+		}
+	}
+	igt_require_f(non_dsc_mode_found,
+		      "No non-DSC mode found on %s\n",
+		      igt_output_name(data->output));
+
+
+	/* Repeatedly force link failure until DSC is required (or link is disabled) */
+	while (!igt_get_dp_link_retrain_disabled(data->drm_fd, data->output)) {
+		mon = igt_watch_uevents();
+
+		igt_assert_f(force_failure_and_wait(data, data->output,
+						    LT_FAILURE_REDUCED_CAPS,
+						    RETRAIN_COUNT, 1.0, 20.0),
+			     "Forcing DSC fallback timed out\n");
+
+		if (igt_get_dp_link_retrain_disabled(data->drm_fd,
+						     data->output)) {
+			igt_reset_connectors();
+			igt_flush_uevents(mon);
+			return;
+		}
+
+		igt_assert_f(wait_for_hotplug_and_check_bad(data->drm_fd,
+							    data,
+							    data->output,
+							    mon,
+							    20.0),
+			     "Didn't get hotplug or link-status=BAD for DSC\n");
+		igt_flush_uevents(mon);
+
+		outputs[output_count++] = data->output;
+		set_connector_link_status_good(data, outputs, &output_count);
+		igt_display_commit2(&data->display, COMMIT_ATOMIC);
+
+		mode_to_check = igt_output_get_mode(data->output);
+
+		if (igt_is_dsc_enabled(data->drm_fd, data->output->name)) {
+			igt_info("mode %dx%d@%d now requires DSC with link rate %d and lane count %d\n",
+				 mode_to_check->hdisplay, mode_to_check->vdisplay,
+				 mode_to_check->vrefresh,
+				 igt_get_current_link_rate(data->drm_fd, data->output),
+				 igt_get_current_lane_count(data->drm_fd, data->output));
+			igt_info("DSC fallback successful on %s\n",
+				 igt_output_name(data->output));
+			dsc_fallback_successful = true;
+			break;
+		} else {
+			igt_info("mode %dx%d@%d still doesn't require DSC\n",
+				 mode_to_check->hdisplay, mode_to_check->vdisplay,
+				 mode_to_check->vrefresh);
+		}
+	}
+	igt_assert_f(dsc_fallback_successful, "DSC fallback unsuccessful\n");
+}
+
+static bool run_lt_fallback_test(data_t *data)
 {
 	bool ran = false;
 	igt_output_t *output;
@@ -366,6 +588,43 @@ static bool run_test(data_t *data)
 	return ran;
 }
 
+static bool run_dsc_sst_fallaback_test(data_t *data)
+{
+	bool ran = false;
+	igt_output_t *output;
+
+	if (!is_dsc_supported_by_source(data->drm_fd)) {
+		igt_info("DSC not supported by source.\n");
+		return ran;
+	}
+
+	for_each_connected_output(&data->display, output) {
+		data->output = output;
+
+		if (!igt_has_force_link_training_failure_debugfs(data->drm_fd,
+								 data->output)) {
+			igt_info("Output %s doesn't support forcing link training.\n",
+				 igt_output_name(data->output));
+			continue;
+		}
+
+		if (output->config.connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) {
+			igt_info("Skipping output %s as it's not DP\n", output->name);
+			continue;
+		}
+
+		if (!is_dsc_supported_by_sink(data->drm_fd, data->output)) {
+			igt_info("Skipping output %s as DSC not supported by sink\n",
+				 igt_output_name(data->output));
+			continue;
+		}
+
+		ran = true;
+		test_dsc_sst_fallback(data);
+	}
+	return ran;
+}
+
 igt_main
 {
 	data_t data = {};
@@ -381,8 +640,13 @@ igt_main
 	}
 
 	igt_subtest("dp-fallback") {
-		igt_require_f(run_test(&data),
-			      "Skipping test as no output found or none supports fallback\n");
+		igt_require_f(run_lt_fallback_test(&data),
+			      "Skipping test as no DP output found or none supports forcing link fail\n");
+	}
+
+	igt_subtest("dsc-fallback") {
+		igt_require_f(run_dsc_sst_fallaback_test(&data),
+			      "Skipping test: DSC fallback conditions not met.\n");
 	}
 
 	igt_fixture {
diff --git a/tests/meson.build b/tests/meson.build
index 2cbd21c2a..dd75976dd 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -367,7 +367,9 @@ extra_sources = {
 	'kms_chamelium_frames': [ join_paths ('chamelium', 'kms_chamelium_helper.c') ],
 	'kms_chamelium_hpd': [ join_paths ('chamelium', 'kms_chamelium_helper.c') ],
 	'kms_dsc': [ join_paths ('intel', 'kms_dsc_helper.c') ],
-	'kms_dp_linktrain_fallback': [join_paths ('intel', 'kms_mst_helper.c')],
+	'kms_dp_linktrain_fallback': [
+           join_paths ('intel', 'kms_mst_helper.c'),
+           join_paths ('intel', 'kms_dsc_helper.c')],
 	'kms_psr2_sf':  [ join_paths ('intel', 'kms_dsc_helper.c') ],
 }
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH i-g-t 1/3] tests/intel/kms_mst_helper: Add helper for MST-related functions
  2025-01-23  7:36 ` [PATCH i-g-t 1/3] tests/intel/kms_mst_helper: Add helper for MST-related functions Kunal Joshi
@ 2025-01-27  7:17   ` Sharma, Swati2
  2025-01-27  8:04     ` Joshi, Kunal1
  0 siblings, 1 reply; 10+ messages in thread
From: Sharma, Swati2 @ 2025-01-27  7:17 UTC (permalink / raw)
  To: Kunal Joshi, igt-dev

Hi Kunal,

If new helper is introduced, please move dp-mst related func() from 
igt_kms.c to

kms_mst_helper.c

On 23-01-2025 01:06 pm, Kunal Joshi wrote:
> This patch introduces kms_mst_helper.c and kms_mst_helper.h
> to centralize commonly used MST-related logic.
> The new function igt_find_all_mst_output_in_topology()
> enumerates MST outputs that share the same root connector,
> simplifying code reuse across tests needing outputs on
> same MST topology. The existing MST-related code in
> kms_dp_linktrain_fallback.c is updated to use the new helper,
> removing duplication. Additionally, meson.build is modified
> to include kms_mst_helper.c in the build process.
>
> Signed-off-by: Kunal Joshi <kunal1.joshi@intel.com>
> ---
>   tests/intel/kms_dp_linktrain_fallback.c | 28 ++++---------------------
>   tests/meson.build                       |  1 +
>   2 files changed, 5 insertions(+), 24 deletions(-)
>
> diff --git a/tests/intel/kms_dp_linktrain_fallback.c b/tests/intel/kms_dp_linktrain_fallback.c
> index a05e2015f..b10946781 100644
> --- a/tests/intel/kms_dp_linktrain_fallback.c
> +++ b/tests/intel/kms_dp_linktrain_fallback.c
> @@ -16,6 +16,7 @@
>   #include <sys/types.h>
>   
>   #include "igt.h"
> +#include "kms_mst_helper.h"
>   
>   /**
>    * SUBTEST: dp-fallback
> @@ -47,28 +48,6 @@ typedef int (*condition_check_fn)(int drm_fd, igt_output_t *output);
>   
>   IGT_TEST_DESCRIPTION("Test link training fallback");
>   
> -static void find_mst_outputs(int drm_fd, data_t *data,
> -			     igt_output_t *output,
> -			     igt_output_t *mst_outputs[],
> -			     int *num_mst_outputs)
> -{
> -	int output_root_id, root_id;
> -	igt_output_t *connector_output;
> -
> -	output_root_id = igt_get_dp_mst_connector_id(output);
> -	/*
> -	 * If output is MST check all other connected output which shares
> -	 * same path and fill mst_outputs and num_mst_outputs
> -	 */
> -	for_each_connected_output(&data->display, connector_output) {
> -		if (!igt_check_output_is_dp_mst(connector_output))
> -			continue;
> -		root_id = igt_get_dp_mst_connector_id(connector_output);
> -		if (((*num_mst_outputs) < IGT_MAX_PIPES) && root_id == output_root_id)
> -			mst_outputs[(*num_mst_outputs)++] = connector_output;
> -	}
> -}
> -
>   static bool setup_mst_outputs(data_t *data, igt_output_t *mst_output[],
>   			      int *output_count)
>   {
> @@ -83,8 +62,9 @@ static bool setup_mst_outputs(data_t *data, igt_output_t *mst_output[],
>   		    traversed_mst_outputs[i] == data->output->config.connector->connector_id)
>   			return false;
>   
> -	find_mst_outputs(data->drm_fd, data, data->output,
> -			 mst_output, output_count);
> +       igt_assert_f(igt_find_all_mst_output_in_topology(data->drm_fd, &data->display, data->output,
> +							mst_output, output_count),
> +		    "Unable to find mst outputs\n");
>   
>   	for (i = 0; i < *output_count; i++) {
>   		output = mst_output[i];
> diff --git a/tests/meson.build b/tests/meson.build
> index 33dffad31..2cbd21c2a 100644
> --- a/tests/meson.build
> +++ b/tests/meson.build
> @@ -367,6 +367,7 @@ extra_sources = {
>   	'kms_chamelium_frames': [ join_paths ('chamelium', 'kms_chamelium_helper.c') ],
>   	'kms_chamelium_hpd': [ join_paths ('chamelium', 'kms_chamelium_helper.c') ],
>   	'kms_dsc': [ join_paths ('intel', 'kms_dsc_helper.c') ],
> +	'kms_dp_linktrain_fallback': [join_paths ('intel', 'kms_mst_helper.c')],
>   	'kms_psr2_sf':  [ join_paths ('intel', 'kms_dsc_helper.c') ],
>   }
>   

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH i-g-t 1/3] tests/intel/kms_mst_helper: Add helper for MST-related functions
  2025-01-27  7:17   ` Sharma, Swati2
@ 2025-01-27  8:04     ` Joshi, Kunal1
  0 siblings, 0 replies; 10+ messages in thread
From: Joshi, Kunal1 @ 2025-01-27  8:04 UTC (permalink / raw)
  To: Sharma, Swati2, igt-dev


On 27-01-2025 12:47, Sharma, Swati2 wrote:
> Hi Kunal,
>
> If new helper is introduced, please move dp-mst related func() from 
> igt_kms.c to
>
> kms_mst_helper.c
Hello Swati,

That is already in plan but will not take that as part of this series.
Will float a separate series for all MST functions to be present in MST 
helper.
Many of them needs modification before integration in the helper.

Thanks and Regards
Kunal Joshi
>
> On 23-01-2025 01:06 pm, Kunal Joshi wrote:
>> This patch introduces kms_mst_helper.c and kms_mst_helper.h
>> to centralize commonly used MST-related logic.
>> The new function igt_find_all_mst_output_in_topology()
>> enumerates MST outputs that share the same root connector,
>> simplifying code reuse across tests needing outputs on
>> same MST topology. The existing MST-related code in
>> kms_dp_linktrain_fallback.c is updated to use the new helper,
>> removing duplication. Additionally, meson.build is modified
>> to include kms_mst_helper.c in the build process.
>>
>> Signed-off-by: Kunal Joshi <kunal1.joshi@intel.com>
>> ---
>>   tests/intel/kms_dp_linktrain_fallback.c | 28 ++++---------------------
>>   tests/meson.build                       |  1 +
>>   2 files changed, 5 insertions(+), 24 deletions(-)
>>
>> diff --git a/tests/intel/kms_dp_linktrain_fallback.c 
>> b/tests/intel/kms_dp_linktrain_fallback.c
>> index a05e2015f..b10946781 100644
>> --- a/tests/intel/kms_dp_linktrain_fallback.c
>> +++ b/tests/intel/kms_dp_linktrain_fallback.c
>> @@ -16,6 +16,7 @@
>>   #include <sys/types.h>
>>     #include "igt.h"
>> +#include "kms_mst_helper.h"
>>     /**
>>    * SUBTEST: dp-fallback
>> @@ -47,28 +48,6 @@ typedef int (*condition_check_fn)(int drm_fd, 
>> igt_output_t *output);
>>     IGT_TEST_DESCRIPTION("Test link training fallback");
>>   -static void find_mst_outputs(int drm_fd, data_t *data,
>> -                 igt_output_t *output,
>> -                 igt_output_t *mst_outputs[],
>> -                 int *num_mst_outputs)
>> -{
>> -    int output_root_id, root_id;
>> -    igt_output_t *connector_output;
>> -
>> -    output_root_id = igt_get_dp_mst_connector_id(output);
>> -    /*
>> -     * If output is MST check all other connected output which shares
>> -     * same path and fill mst_outputs and num_mst_outputs
>> -     */
>> -    for_each_connected_output(&data->display, connector_output) {
>> -        if (!igt_check_output_is_dp_mst(connector_output))
>> -            continue;
>> -        root_id = igt_get_dp_mst_connector_id(connector_output);
>> -        if (((*num_mst_outputs) < IGT_MAX_PIPES) && root_id == 
>> output_root_id)
>> -            mst_outputs[(*num_mst_outputs)++] = connector_output;
>> -    }
>> -}
>> -
>>   static bool setup_mst_outputs(data_t *data, igt_output_t 
>> *mst_output[],
>>                     int *output_count)
>>   {
>> @@ -83,8 +62,9 @@ static bool setup_mst_outputs(data_t *data, 
>> igt_output_t *mst_output[],
>>               traversed_mst_outputs[i] == 
>> data->output->config.connector->connector_id)
>>               return false;
>>   -    find_mst_outputs(data->drm_fd, data, data->output,
>> -             mst_output, output_count);
>> + igt_assert_f(igt_find_all_mst_output_in_topology(data->drm_fd, 
>> &data->display, data->output,
>> +                            mst_output, output_count),
>> +            "Unable to find mst outputs\n");
>>         for (i = 0; i < *output_count; i++) {
>>           output = mst_output[i];
>> diff --git a/tests/meson.build b/tests/meson.build
>> index 33dffad31..2cbd21c2a 100644
>> --- a/tests/meson.build
>> +++ b/tests/meson.build
>> @@ -367,6 +367,7 @@ extra_sources = {
>>       'kms_chamelium_frames': [ join_paths ('chamelium', 
>> 'kms_chamelium_helper.c') ],
>>       'kms_chamelium_hpd': [ join_paths ('chamelium', 
>> 'kms_chamelium_helper.c') ],
>>       'kms_dsc': [ join_paths ('intel', 'kms_dsc_helper.c') ],
>> +    'kms_dp_linktrain_fallback': [join_paths ('intel', 
>> 'kms_mst_helper.c')],
>>       'kms_psr2_sf':  [ join_paths ('intel', 'kms_dsc_helper.c') ],
>>   }

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH i-g-t 2/3] tests/intel/kms_dp_linktrain_fallback: add dsc-fallback test
  2025-01-27  6:29 ` [PATCH i-g-t 2/3] tests/intel/kms_dp_linktrain_fallback: " Kunal Joshi
@ 2025-01-27  9:17   ` Sharma, Swati2
  2025-02-10  9:56   ` Nautiyal, Ankit K
  1 sibling, 0 replies; 10+ messages in thread
From: Sharma, Swati2 @ 2025-01-27  9:17 UTC (permalink / raw)
  To: Kunal Joshi, igt-dev; +Cc: Ankit Nautiyal

Hi Kunal,

Please have consistency in subject of your patches.
Either start subject with capital letter or small letter.

Also, please update igt_test_description()

On 27-01-2025 11:59 am, Kunal Joshi wrote:
> add new dsc-fallback test which finds a mode
%s add/Add
> which can be driven without DSC at current link
> params and reduces link param till we have
> combination (link_rate, lane_count) which requires
> DSC to be enabled.
>
> Cc: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
> Signed-off-by: Kunal Joshi <kunal1.joshi@intel.com>
> ---
>   tests/intel/kms_dp_linktrain_fallback.c | 352 +++++++++++++++++++++---
>   tests/meson.build                       |   4 +-
>   2 files changed, 311 insertions(+), 45 deletions(-)
>
> diff --git a/tests/intel/kms_dp_linktrain_fallback.c b/tests/intel/kms_dp_linktrain_fallback.c
> index b10946781..471381f1d 100644
> --- a/tests/intel/kms_dp_linktrain_fallback.c
> +++ b/tests/intel/kms_dp_linktrain_fallback.c
> @@ -17,10 +17,14 @@
>   
>   #include "igt.h"
>   #include "kms_mst_helper.h"
> +#include "kms_dsc_helper.h"
>   
>   /**
>    * SUBTEST: dp-fallback
>    * Description: Test fallback on DP connectors
> + *
> + * SUBTEST: dsc-fallback
> + * Description: Test we fallback to DSC when BW isn't sufficient
Remove "we"
>    */
>   
>   #define RETRAIN_COUNT 1
> @@ -238,16 +242,124 @@ static int check_condition_with_timeout(int drm_fd, igt_output_t *output,
>   	}
>   }
>   
> +/*
> + * Force a link training failure followed by link retrain, then
> + * block until the driver has no further pending retrain/failure.
> + * Returns false if we time out waiting.
> + */
> +static bool force_failure_and_wait(data_t *data,
> +				   igt_output_t *output,
> +				   int failure_type,
> +				   int retrain_count,
> +				   double interval,
> +				   double timeout)
> +{
> +	igt_force_lt_failure(data->drm_fd, output, failure_type);
> +	igt_force_link_retrain(data->drm_fd, output, retrain_count);
> +
> +	/* Wait until there's no pending retrain */
> +	if (check_condition_with_timeout(data->drm_fd, output,
> +					 igt_get_dp_pending_retrain,
> +					 interval, timeout)) {
> +		igt_info("Timed out waiting for pending retrain.\n");
> +		return false;
> +	}
> +
> +	/* Wait until there's no pending LT failures */
> +	if (check_condition_with_timeout(data->drm_fd, output,
> +					 igt_get_dp_pending_lt_failures,
> +					 interval, timeout)) {
> +		igt_info("Timed out waiting for pending LT failures.\n");
> +		return false;
> +	}
> +
> +	return true;
> +}
> +
> +/*
> + * Waits for a hotplug event, then checks that the link-status is BAD.
> + * Returns false if the link-status isn't BAD or no hotplug arrives in time.
> + */
> +static bool wait_for_hotplug_and_check_bad(int drm_fd,
> +					   data_t *data,
> +					   igt_output_t *output,
> +					   struct udev_monitor *mon,
> +					   double hotplug_timeout)
> +{
> +	uint32_t link_status_prop_id;
> +	uint64_t link_status_value;
> +	drmModePropertyPtr link_status_prop;
> +
> +	if (!igt_hotplug_detected(mon, hotplug_timeout)) {
> +		igt_info("No hotplug event within %.2f seconds.\n", hotplug_timeout);
> +		return false;
> +	}
> +
> +	kmstest_get_property(drm_fd,
> +			     output->config.connector->connector_id,
> +			     DRM_MODE_OBJECT_CONNECTOR,
> +			     "link-status",
> +			     &link_status_prop_id, &link_status_value,
> +			     &link_status_prop);
> +
> +	if (link_status_value != DRM_MODE_LINK_STATUS_BAD) {
> +		igt_info("Expected link-status=BAD but got %" PRIu64 "\n",
> +			 link_status_value);
> +		return false;
> +	}
> +
> +	return true;
> +}
> +
> +/*
> + * Sets link status=GOOD for the specified outputs, then calls
> + * validate_modeset_for_outputs() to re-commit. Returns false
> + * if the re-commit fails.
> + */
> +static bool fix_link_status_and_recommit(data_t *data,
> +					 igt_output_t *outputs[],
> +					 int *output_count,
> +					 drmModeModeInfo * modes[],
> +					 struct igt_fb fbs[],
> +					 struct igt_plane *primarys[])
> +{
> +	int i;
> +	igt_output_t *out;
> +
> +	/* Set link-status=GOOD on each tested output */
> +	for_each_connected_output(&data->display, out) {
> +		for (i = 0; i < *output_count; i++) {
> +			if (out->id == outputs[i]->id) {
> +				igt_output_set_prop_value(
> +					out, IGT_CONNECTOR_LINK_STATUS,
> +					DRM_MODE_LINK_STATUS_GOOD);
> +			}
> +		}
> +	}
> +
> +	if (!validate_modeset_for_outputs(data, outputs, output_count,
> +					  modes, fbs, primarys)) {
> +		igt_info("Modeset validation failed after forcing link-status=GOOD.\n");
> +		return false;
> +	}
> +
> +	if (igt_display_try_commit_atomic(&data->display,
> +					  DRM_MODE_ATOMIC_ALLOW_MODESET,
> +					  NULL) != 0) {
> +		igt_info("Commit failed after restoring link-status=GOOD.\n");
> +		return false;
> +	}
> +
> +	return true;
> +}
> +
>   static void test_fallback(data_t *data, bool is_mst)
>   {
>   	int output_count, retries;
>   	int max_link_rate, curr_link_rate, prev_link_rate;
>   	int max_lane_count, curr_lane_count, prev_lane_count;
>   	igt_output_t *outputs[IGT_MAX_PIPES];
> -	uint32_t link_status_prop_id;
> -	uint64_t link_status_value;
> -	drmModeModeInfo *modes[IGT_MAX_PIPES];
> -	drmModePropertyPtr link_status_prop;
> +	drmModeModeInfo * modes[IGT_MAX_PIPES];
>   	struct igt_fb fbs[IGT_MAX_PIPES];
>   	struct igt_plane *primarys[IGT_MAX_PIPES];
>   	struct udev_monitor *mon;
> @@ -256,71 +368,71 @@ static void test_fallback(data_t *data, bool is_mst)
>   
>   	igt_display_reset(&data->display);
>   	igt_reset_link_params(data->drm_fd, data->output);
> -	if (!setup_outputs(data, is_mst, outputs,
> -			   &output_count, modes, fbs,
> -			   primarys))
> +	igt_force_link_retrain(data->drm_fd, data->output, 1);
> +
> +	if (!setup_outputs(data, is_mst, outputs, &output_count,
> +			   modes, fbs, primarys))
>   		return;
>   
>   	igt_info("Testing link training fallback on %s\n",
>   		 igt_output_name(data->output));
>   	max_link_rate = igt_get_max_link_rate(data->drm_fd, data->output);
>   	max_lane_count = igt_get_max_lane_count(data->drm_fd, data->output);
> +
>   	prev_link_rate = igt_get_current_link_rate(data->drm_fd, data->output);
>   	prev_lane_count = igt_get_current_lane_count(data->drm_fd, data->output);
>   
> -	while (!igt_get_dp_link_retrain_disabled(data->drm_fd,
> -						 data->output)) {
> +	while (!igt_get_dp_link_retrain_disabled(data->drm_fd, data->output)) {
>   		igt_info("Current link rate: %d, Current lane count: %d\n",
> -			 prev_link_rate,
> -			 prev_lane_count);
> +			 prev_link_rate, prev_lane_count);
> +
>   		mon = igt_watch_uevents();
> -		igt_force_lt_failure(data->drm_fd, data->output,
> -				     LT_FAILURE_REDUCED_CAPS);
> -		igt_force_link_retrain(data->drm_fd, data->output,
> -				       RETRAIN_COUNT);
> -
> -		igt_assert_eq(check_condition_with_timeout(data->drm_fd,
> -							   data->output,
> -							   igt_get_dp_pending_retrain,
> -							   1.0, 20.0), 0);
> -		igt_assert_eq(check_condition_with_timeout(data->drm_fd,
> -							   data->output,
> -							   igt_get_dp_pending_lt_failures,
> -							   1.0, 20.0), 0);
> +
> +		/* Force link failure, wait for retrain to clear */
> +		igt_assert_f(force_failure_and_wait(data, data->output,
> +						    LT_FAILURE_REDUCED_CAPS,
> +						    RETRAIN_COUNT,
> +						    1.0, 20.0),
> +			     "Link training failure steps timed out\n");
>   
>   		if (igt_get_dp_link_retrain_disabled(data->drm_fd,
>   						     data->output)) {
>   			igt_reset_connectors();
> +			igt_flush_uevents(mon);
>   			return;
>   		}
>   
> -		igt_assert_f(igt_hotplug_detected(mon, 20),
> -			     "Didn't get hotplug for force link training failure\n");
> -
> -		kmstest_get_property(data->drm_fd,
> -				data->output->config.connector->connector_id,
> -				DRM_MODE_OBJECT_CONNECTOR, "link-status",
> -				&link_status_prop_id, &link_status_value,
> -				&link_status_prop);
> -		igt_assert_eq(link_status_value, DRM_MODE_LINK_STATUS_BAD);
> +		/* Wait for hotplug + check link-status=BAD */
> +		igt_assert_f(wait_for_hotplug_and_check_bad(data->drm_fd,
> +							    data,
> +							    data->output,
> +							    mon,
> +							    20.0),
> +			     "Didn't get hotplug or link-status=BAD\n");
>   		igt_flush_uevents(mon);
> -		set_connector_link_status_good(data, outputs, &output_count);
> -		igt_assert_f(validate_modeset_for_outputs(data,
> +
> +		/* Set link-status=GOOD and re-commit */
> +		igt_assert_f(fix_link_status_and_recommit(data,
>   							  outputs,
>   							  &output_count,
>   							  modes,
>   							  fbs,
>   							  primarys),
>   			     "modeset failed\n");
> -		igt_display_commit2(&data->display, COMMIT_ATOMIC);
>   
> -		igt_assert_eq(data->output->values[IGT_CONNECTOR_LINK_STATUS], DRM_MODE_LINK_STATUS_GOOD);
> -		curr_link_rate = igt_get_current_link_rate(data->drm_fd, data->output);
> -		curr_lane_count = igt_get_current_lane_count(data->drm_fd, data->output);
> +		/* Ensure link-status is GOOD again */
> +		igt_assert_eq(data->output->values[IGT_CONNECTOR_LINK_STATUS],
> +			      DRM_MODE_LINK_STATUS_GOOD);
> +
> +		curr_link_rate = igt_get_current_link_rate(data->drm_fd,
> +							   data->output);
> +		curr_lane_count = igt_get_current_lane_count(data->drm_fd,
> +							     data->output);
>   
>   		igt_assert_f((curr_link_rate < prev_link_rate ||
> -			     curr_lane_count < prev_lane_count) ||
> -			     ((curr_link_rate == max_link_rate && curr_lane_count == max_lane_count) && --retries),
> +			      curr_lane_count < prev_lane_count) ||
> +			     ((curr_link_rate == max_link_rate &&
> +			       curr_lane_count == max_lane_count) && --retries),
>   			     "Fallback unsuccessful\n");
>   
>   		prev_link_rate = curr_link_rate;
> @@ -328,7 +440,117 @@ static void test_fallback(data_t *data, bool is_mst)
>   	}
>   }
>   
> -static bool run_test(data_t *data)
> +static void test_dsc_sst_fallback(data_t *data)
> +{
> +	bool non_dsc_mode_found = false;
> +	bool dsc_fallback_successful = false;
> +	int ret;
> +	struct udev_monitor *mon;
> +	drmModeModeInfo *mode_to_check;
> +	igt_output_t *outputs[IGT_MAX_PIPES];
> +	int output_count = 0;
> +
> +	igt_info("Checking DSC fallback on %s\n", igt_output_name(data->output));
> +	data->pipe = PIPE_A;
> +
> +        igt_display_reset(&data->display);
> +        igt_reset_link_params(data->drm_fd, data->output);
Fix indentation here.
> +	igt_force_link_retrain(data->drm_fd, data->output, 1);
> +
> +	/* Find a mode that doesn't require DSC initially */
> +	for_each_connector_mode(data->output) {
> +		data->mode = &data->output->config.connector->modes[j__];
> +		igt_create_color_fb(data->drm_fd, data->mode->hdisplay,
> +				    data->mode->vdisplay, DRM_FORMAT_XRGB8888,
> +				    DRM_FORMAT_MOD_LINEAR, 0.0, 1.0, 0.0,
> +				    &data->fb);
> +		igt_output_override_mode(data->output, data->mode);
> +		igt_output_set_pipe(data->output, data->pipe);
> +		data->primary = igt_output_get_plane_type(data->output,
> +						DRM_PLANE_TYPE_PRIMARY);
> +		igt_plane_set_fb(data->primary, &data->fb);
> +
> +		ret = igt_display_try_commit_atomic(&data->display,
> +						    DRM_MODE_ATOMIC_TEST_ONLY |
> +						    DRM_MODE_ATOMIC_ALLOW_MODESET,
> +						    NULL);
> +		if (ret != 0) {
> +			igt_info("Skipping mode %dx%d@%d on %s\n",
> +				 data->mode->hdisplay, data->mode->vdisplay,
> +				 data->mode->vrefresh,
> +				 igt_output_name(data->output));
> +			continue;
> +		}
> +		igt_display_commit2(&data->display, COMMIT_ATOMIC);
> +
> +		if (!igt_is_dsc_enabled(data->drm_fd,
> +					data->output->name)) {
> +			drmModeModeInfo *non_dsc_mode
> +				= igt_output_get_mode(data->output);
> +			igt_info("Found mode %dx%d@%d %s that doesn't need DSC with link rate %d and lane count %d\n",
> +				 non_dsc_mode->hdisplay, non_dsc_mode->vdisplay,
> +				 non_dsc_mode->vrefresh, non_dsc_mode->name,
> +				 igt_get_current_link_rate(data->drm_fd, data->output),
> +				 igt_get_current_lane_count(data->drm_fd, data->output));
> +			non_dsc_mode_found = true;
> +			break;
> +		}
> +	}
> +	igt_require_f(non_dsc_mode_found,
> +		      "No non-DSC mode found on %s\n",
> +		      igt_output_name(data->output));
> +
> +
Remove extra new line
> +	/* Repeatedly force link failure until DSC is required (or link is disabled) */
> +	while (!igt_get_dp_link_retrain_disabled(data->drm_fd, data->output)) {
> +		mon = igt_watch_uevents();
> +
> +		igt_assert_f(force_failure_and_wait(data, data->output,
> +						    LT_FAILURE_REDUCED_CAPS,
> +						    RETRAIN_COUNT, 1.0, 20.0),
> +			     "Forcing DSC fallback timed out\n");
> +
> +		if (igt_get_dp_link_retrain_disabled(data->drm_fd,
> +						     data->output)) {
> +			igt_reset_connectors();
> +			igt_flush_uevents(mon);
> +			return;
> +		}
> +
> +		igt_assert_f(wait_for_hotplug_and_check_bad(data->drm_fd,
> +							    data,
> +							    data->output,
> +							    mon,
> +							    20.0),
> +			     "Didn't get hotplug or link-status=BAD for DSC\n");
> +		igt_flush_uevents(mon);
> +
> +		outputs[output_count++] = data->output;
> +		set_connector_link_status_good(data, outputs, &output_count);
> +		igt_display_commit2(&data->display, COMMIT_ATOMIC);
> +
> +		mode_to_check = igt_output_get_mode(data->output);
> +
> +		if (igt_is_dsc_enabled(data->drm_fd, data->output->name)) {
> +			igt_info("mode %dx%d@%d now requires DSC with link rate %d and lane count %d\n",
> +				 mode_to_check->hdisplay, mode_to_check->vdisplay,
> +				 mode_to_check->vrefresh,
> +				 igt_get_current_link_rate(data->drm_fd, data->output),
> +				 igt_get_current_lane_count(data->drm_fd, data->output));
> +			igt_info("DSC fallback successful on %s\n",
> +				 igt_output_name(data->output));
> +			dsc_fallback_successful = true;
> +			break;
> +		} else {
> +			igt_info("mode %dx%d@%d still doesn't require DSC\n",
> +				 mode_to_check->hdisplay, mode_to_check->vdisplay,
> +				 mode_to_check->vrefresh);
> +		}
> +	}
> +	igt_assert_f(dsc_fallback_successful, "DSC fallback unsuccessful\n");
> +}
> +
> +static bool run_lt_fallback_test(data_t *data)
>   {
>   	bool ran = false;
>   	igt_output_t *output;
> @@ -366,6 +588,43 @@ static bool run_test(data_t *data)
>   	return ran;
>   }
>   
> +static bool run_dsc_sst_fallaback_test(data_t *data)
> +{
> +	bool ran = false;
> +	igt_output_t *output;
> +
> +	if (!is_dsc_supported_by_source(data->drm_fd)) {
> +		igt_info("DSC not supported by source.\n");
> +		return ran;
> +	}
> +
> +	for_each_connected_output(&data->display, output) {
> +		data->output = output;
> +
> +		if (!igt_has_force_link_training_failure_debugfs(data->drm_fd,
> +								 data->output)) {
> +			igt_info("Output %s doesn't support forcing link training.\n",
> +				 igt_output_name(data->output));
> +			continue;
> +		}
> +
> +		if (output->config.connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) {
> +			igt_info("Skipping output %s as it's not DP\n", output->name);
> +			continue;
> +		}
> +
> +		if (!is_dsc_supported_by_sink(data->drm_fd, data->output)) {
> +			igt_info("Skipping output %s as DSC not supported by sink\n",
> +				 igt_output_name(data->output));
> +			continue;
> +		}
> +
> +		ran = true;
> +		test_dsc_sst_fallback(data);
> +	}
> +	return ran;
> +}
> +
>   igt_main
>   {
>   	data_t data = {};
> @@ -381,8 +640,13 @@ igt_main
>   	}
>   
>   	igt_subtest("dp-fallback") {
> -		igt_require_f(run_test(&data),
> -			      "Skipping test as no output found or none supports fallback\n");
> +		igt_require_f(run_lt_fallback_test(&data),
> +			      "Skipping test as no DP output found or none supports forcing link fail\n");
This rename and update of skip message should have been a separate patch.
> +	}
> +
> +	igt_subtest("dsc-fallback") {
> +		igt_require_f(run_dsc_sst_fallaback_test(&data),
> +			      "Skipping test: DSC fallback conditions not met.\n");
This should be in this patch only.
>   	}
>   
>   	igt_fixture {
> diff --git a/tests/meson.build b/tests/meson.build
> index 2cbd21c2a..dd75976dd 100644
> --- a/tests/meson.build
> +++ b/tests/meson.build
> @@ -367,7 +367,9 @@ extra_sources = {
>   	'kms_chamelium_frames': [ join_paths ('chamelium', 'kms_chamelium_helper.c') ],
>   	'kms_chamelium_hpd': [ join_paths ('chamelium', 'kms_chamelium_helper.c') ],
>   	'kms_dsc': [ join_paths ('intel', 'kms_dsc_helper.c') ],
> -	'kms_dp_linktrain_fallback': [join_paths ('intel', 'kms_mst_helper.c')],
> +	'kms_dp_linktrain_fallback': [
> +           join_paths ('intel', 'kms_mst_helper.c'),
> +           join_paths ('intel', 'kms_dsc_helper.c')],
>   	'kms_psr2_sf':  [ join_paths ('intel', 'kms_dsc_helper.c') ],
>   }
>   

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH i-g-t 2/3] tests/intel/kms_dp_linktrain_fallback: add dsc-fallback test
  2025-01-27  6:29 ` [PATCH i-g-t 2/3] tests/intel/kms_dp_linktrain_fallback: " Kunal Joshi
  2025-01-27  9:17   ` Sharma, Swati2
@ 2025-02-10  9:56   ` Nautiyal, Ankit K
  1 sibling, 0 replies; 10+ messages in thread
From: Nautiyal, Ankit K @ 2025-02-10  9:56 UTC (permalink / raw)
  To: Kunal Joshi, igt-dev


On 1/27/2025 11:59 AM, Kunal Joshi wrote:
> add new dsc-fallback test which finds a mode
> which can be driven without DSC at current link
> params and reduces link param till we have
> combination (link_rate, lane_count) which requires
> DSC to be enabled.
This does not specify what the test_dsc_fallback is validating or why a 
new test is required.

What perhaps should be mentioned is that we want to check whether DSC 
automatically kicks in while falling back to a lower rate/lane.

And then the above lines make sense.


>
> Cc: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
> Signed-off-by: Kunal Joshi <kunal1.joshi@intel.com>
> ---
>   tests/intel/kms_dp_linktrain_fallback.c | 352 +++++++++++++++++++++---
>   tests/meson.build                       |   4 +-
>   2 files changed, 311 insertions(+), 45 deletions(-)
>
> diff --git a/tests/intel/kms_dp_linktrain_fallback.c b/tests/intel/kms_dp_linktrain_fallback.c
> index b10946781..471381f1d 100644
> --- a/tests/intel/kms_dp_linktrain_fallback.c
> +++ b/tests/intel/kms_dp_linktrain_fallback.c
> @@ -17,10 +17,14 @@
>   
>   #include "igt.h"
>   #include "kms_mst_helper.h"
> +#include "kms_dsc_helper.h"
>   
>   /**
>    * SUBTEST: dp-fallback
>    * Description: Test fallback on DP connectors
> + *
> + * SUBTEST: dsc-fallback
> + * Description: Test we fallback to DSC when BW isn't sufficient
>    */
>   
>   #define RETRAIN_COUNT 1
> @@ -238,16 +242,124 @@ static int check_condition_with_timeout(int drm_fd, igt_output_t *output,
>   	}
>   }
>   
> +/*
> + * Force a link training failure followed by link retrain, then
> + * block until the driver has no further pending retrain/failure.
> + * Returns false if we time out waiting.
> + */
> +static bool force_failure_and_wait(data_t *data,
> +				   igt_output_t *output,
> +				   int failure_type,
> +				   int retrain_count,
> +				   double interval,
> +				   double timeout)
> +{
> +	igt_force_lt_failure(data->drm_fd, output, failure_type);
> +	igt_force_link_retrain(data->drm_fd, output, retrain_count);
> +
> +	/* Wait until there's no pending retrain */
> +	if (check_condition_with_timeout(data->drm_fd, output,
> +					 igt_get_dp_pending_retrain,
> +					 interval, timeout)) {
> +		igt_info("Timed out waiting for pending retrain.\n");
> +		return false;
> +	}
> +
> +	/* Wait until there's no pending LT failures */
> +	if (check_condition_with_timeout(data->drm_fd, output,
> +					 igt_get_dp_pending_lt_failures,
> +					 interval, timeout)) {
> +		igt_info("Timed out waiting for pending LT failures.\n");
> +		return false;
> +	}
> +
> +	return true;
> +}
> +
> +/*
> + * Waits for a hotplug event, then checks that the link-status is BAD.
> + * Returns false if the link-status isn't BAD or no hotplug arrives in time.
> + */
> +static bool wait_for_hotplug_and_check_bad(int drm_fd,
> +					   data_t *data,
> +					   igt_output_t *output,
> +					   struct udev_monitor *mon,
> +					   double hotplug_timeout)
> +{
> +	uint32_t link_status_prop_id;
> +	uint64_t link_status_value;
> +	drmModePropertyPtr link_status_prop;
> +
> +	if (!igt_hotplug_detected(mon, hotplug_timeout)) {
> +		igt_info("No hotplug event within %.2f seconds.\n", hotplug_timeout);
> +		return false;
> +	}
> +
> +	kmstest_get_property(drm_fd,
> +			     output->config.connector->connector_id,
> +			     DRM_MODE_OBJECT_CONNECTOR,
> +			     "link-status",
> +			     &link_status_prop_id, &link_status_value,
> +			     &link_status_prop);
> +
> +	if (link_status_value != DRM_MODE_LINK_STATUS_BAD) {
> +		igt_info("Expected link-status=BAD but got %" PRIu64 "\n",
> +			 link_status_value);
> +		return false;
> +	}
> +
> +	return true;
> +}
> +
> +/*
> + * Sets link status=GOOD for the specified outputs, then calls
> + * validate_modeset_for_outputs() to re-commit. Returns false
> + * if the re-commit fails.
> + */
> +static bool fix_link_status_and_recommit(data_t *data,
> +					 igt_output_t *outputs[],
> +					 int *output_count,
> +					 drmModeModeInfo * modes[],
> +					 struct igt_fb fbs[],
> +					 struct igt_plane *primarys[])
> +{
> +	int i;
> +	igt_output_t *out;
> +
> +	/* Set link-status=GOOD on each tested output */
> +	for_each_connected_output(&data->display, out) {
> +		for (i = 0; i < *output_count; i++) {
> +			if (out->id == outputs[i]->id) {
> +				igt_output_set_prop_value(
> +					out, IGT_CONNECTOR_LINK_STATUS,
> +					DRM_MODE_LINK_STATUS_GOOD);
> +			}
> +		}
> +	}
> +
> +	if (!validate_modeset_for_outputs(data, outputs, output_count,
> +					  modes, fbs, primarys)) {
> +		igt_info("Modeset validation failed after forcing link-status=GOOD.\n");
> +		return false;
> +	}
> +
> +	if (igt_display_try_commit_atomic(&data->display,
> +					  DRM_MODE_ATOMIC_ALLOW_MODESET,
> +					  NULL) != 0) {
> +		igt_info("Commit failed after restoring link-status=GOOD.\n");
> +		return false;
> +	}
> +
> +	return true;
> +}
> +
>   static void test_fallback(data_t *data, bool is_mst)
>   {
>   	int output_count, retries;
>   	int max_link_rate, curr_link_rate, prev_link_rate;
>   	int max_lane_count, curr_lane_count, prev_lane_count;
>   	igt_output_t *outputs[IGT_MAX_PIPES];
> -	uint32_t link_status_prop_id;
> -	uint64_t link_status_value;
> -	drmModeModeInfo *modes[IGT_MAX_PIPES];
> -	drmModePropertyPtr link_status_prop;
> +	drmModeModeInfo * modes[IGT_MAX_PIPES];
>   	struct igt_fb fbs[IGT_MAX_PIPES];
>   	struct igt_plane *primarys[IGT_MAX_PIPES];
>   	struct udev_monitor *mon;
> @@ -256,71 +368,71 @@ static void test_fallback(data_t *data, bool is_mst)
>   
>   	igt_display_reset(&data->display);
>   	igt_reset_link_params(data->drm_fd, data->output);
> -	if (!setup_outputs(data, is_mst, outputs,
> -			   &output_count, modes, fbs,
> -			   primarys))
> +	igt_force_link_retrain(data->drm_fd, data->output, 1);

This is new. Not sure why this is required now in the test_fallback.



> +
> +	if (!setup_outputs(data, is_mst, outputs, &output_count,
> +			   modes, fbs, primarys))

Formatting or style change should not be fixed with functional change.

>   		return;
>   
>   	igt_info("Testing link training fallback on %s\n",
>   		 igt_output_name(data->output));
>   	max_link_rate = igt_get_max_link_rate(data->drm_fd, data->output);
>   	max_lane_count = igt_get_max_lane_count(data->drm_fd, data->output);
> +
>   	prev_link_rate = igt_get_current_link_rate(data->drm_fd, data->output);
>   	prev_lane_count = igt_get_current_lane_count(data->drm_fd, data->output);
>   
> -	while (!igt_get_dp_link_retrain_disabled(data->drm_fd,
> -						 data->output)) {
> +	while (!igt_get_dp_link_retrain_disabled(data->drm_fd, data->output)) {

This change is not required.


>   		igt_info("Current link rate: %d, Current lane count: %d\n",
> -			 prev_link_rate,
> -			 prev_lane_count);
> +			 prev_link_rate, prev_lane_count);
> +

These changes are not required.


>   		mon = igt_watch_uevents();
> -		igt_force_lt_failure(data->drm_fd, data->output,
> -				     LT_FAILURE_REDUCED_CAPS);
> -		igt_force_link_retrain(data->drm_fd, data->output,
> -				       RETRAIN_COUNT);
> -
> -		igt_assert_eq(check_condition_with_timeout(data->drm_fd,
> -							   data->output,
> -							   igt_get_dp_pending_retrain,
> -							   1.0, 20.0), 0);
> -		igt_assert_eq(check_condition_with_timeout(data->drm_fd,
> -							   data->output,
> -							   igt_get_dp_pending_lt_failures,
> -							   1.0, 20.0), 0);

This change should be a separate patch.

Basically one patch to introduce force_failure_and_wait and use it in 
this test.

Then add new dsc fallback test where this is re-used.


> +
> +		/* Force link failure, wait for retrain to clear */
> +		igt_assert_f(force_failure_and_wait(data, data->output,
> +						    LT_FAILURE_REDUCED_CAPS,
> +						    RETRAIN_COUNT,
> +						    1.0, 20.0),
> +			     "Link training failure steps timed out\n");
>   
>   		if (igt_get_dp_link_retrain_disabled(data->drm_fd,
>   						     data->output)) {
>   			igt_reset_connectors();
> +			igt_flush_uevents(mon);
>   			return;
>   		}
>   
> -		igt_assert_f(igt_hotplug_detected(mon, 20),
> -			     "Didn't get hotplug for force link training failure\n");
> -
> -		kmstest_get_property(data->drm_fd,
> -				data->output->config.connector->connector_id,
> -				DRM_MODE_OBJECT_CONNECTOR, "link-status",
> -				&link_status_prop_id, &link_status_value,
> -				&link_status_prop);
> -		igt_assert_eq(link_status_value, DRM_MODE_LINK_STATUS_BAD);
> +		/* Wait for hotplug + check link-status=BAD */
> +		igt_assert_f(wait_for_hotplug_and_check_bad(data->drm_fd,
> +							    data,
> +							    data->output,
> +							    mon,
> +							    20.0),
> +			     "Didn't get hotplug or link-status=BAD\n");
>   		igt_flush_uevents(mon);
> -		set_connector_link_status_good(data, outputs, &output_count);
> -		igt_assert_f(validate_modeset_for_outputs(data,
> +
> +		/* Set link-status=GOOD and re-commit */
> +		igt_assert_f(fix_link_status_and_recommit(data,
>   							  outputs,
>   							  &output_count,
>   							  modes,
>   							  fbs,
>   							  primarys),
>   			     "modeset failed\n");
> -		igt_display_commit2(&data->display, COMMIT_ATOMIC);
>   
> -		igt_assert_eq(data->output->values[IGT_CONNECTOR_LINK_STATUS], DRM_MODE_LINK_STATUS_GOOD);
> -		curr_link_rate = igt_get_current_link_rate(data->drm_fd, data->output);
> -		curr_lane_count = igt_get_current_lane_count(data->drm_fd, data->output);
> +		/* Ensure link-status is GOOD again */
> +		igt_assert_eq(data->output->values[IGT_CONNECTOR_LINK_STATUS],
> +			      DRM_MODE_LINK_STATUS_GOOD);
> +
> +		curr_link_rate = igt_get_current_link_rate(data->drm_fd,
> +							   data->output);
> +		curr_lane_count = igt_get_current_lane_count(data->drm_fd,
> +							     data->output);
>   
>   		igt_assert_f((curr_link_rate < prev_link_rate ||
> -			     curr_lane_count < prev_lane_count) ||
> -			     ((curr_link_rate == max_link_rate && curr_lane_count == max_lane_count) && --retries),
> +			      curr_lane_count < prev_lane_count) ||
> +			     ((curr_link_rate == max_link_rate &&
> +			       curr_lane_count == max_lane_count) && --retries),
>   			     "Fallback unsuccessful\n");
>   
>   		prev_link_rate = curr_link_rate;
> @@ -328,7 +440,117 @@ static void test_fallback(data_t *data, bool is_mst)
>   	}
>   }
>   
> -static bool run_test(data_t *data)
> +static void test_dsc_sst_fallback(data_t *data)
> +{
> +	bool non_dsc_mode_found = false;
> +	bool dsc_fallback_successful = false;
> +	int ret;
> +	struct udev_monitor *mon;
> +	drmModeModeInfo *mode_to_check;
> +	igt_output_t *outputs[IGT_MAX_PIPES];
> +	int output_count = 0;
> +
> +	igt_info("Checking DSC fallback on %s\n", igt_output_name(data->output));
> +	data->pipe = PIPE_A;
> +
> +        igt_display_reset(&data->display);
> +        igt_reset_link_params(data->drm_fd, data->output);
> +	igt_force_link_retrain(data->drm_fd, data->output, 1);
> +
> +	/* Find a mode that doesn't require DSC initially */
> +	for_each_connector_mode(data->output) {
> +		data->mode = &data->output->config.connector->modes[j__];
> +		igt_create_color_fb(data->drm_fd, data->mode->hdisplay,
> +				    data->mode->vdisplay, DRM_FORMAT_XRGB8888,
> +				    DRM_FORMAT_MOD_LINEAR, 0.0, 1.0, 0.0,
> +				    &data->fb);
> +		igt_output_override_mode(data->output, data->mode);
> +		igt_output_set_pipe(data->output, data->pipe);
> +		data->primary = igt_output_get_plane_type(data->output,
> +						DRM_PLANE_TYPE_PRIMARY);
> +		igt_plane_set_fb(data->primary, &data->fb);
> +
> +		ret = igt_display_try_commit_atomic(&data->display,
> +						    DRM_MODE_ATOMIC_TEST_ONLY |
> +						    DRM_MODE_ATOMIC_ALLOW_MODESET,
> +						    NULL);
> +		if (ret != 0) {
> +			igt_info("Skipping mode %dx%d@%d on %s\n",
> +				 data->mode->hdisplay, data->mode->vdisplay,
> +				 data->mode->vrefresh,
> +				 igt_output_name(data->output));

IMO, this can be igt_debug. It might flood with lots of messages while 
iterating through the modes.

The new subtest looks fine to me.


Regards,

Ankit


> +			continue;
> +		}
> +		igt_display_commit2(&data->display, COMMIT_ATOMIC);
> +
> +		if (!igt_is_dsc_enabled(data->drm_fd,
> +					data->output->name)) {
> +			drmModeModeInfo *non_dsc_mode
> +				= igt_output_get_mode(data->output);
> +			igt_info("Found mode %dx%d@%d %s that doesn't need DSC with link rate %d and lane count %d\n",
> +				 non_dsc_mode->hdisplay, non_dsc_mode->vdisplay,
> +				 non_dsc_mode->vrefresh, non_dsc_mode->name,
> +				 igt_get_current_link_rate(data->drm_fd, data->output),
> +				 igt_get_current_lane_count(data->drm_fd, data->output));
> +			non_dsc_mode_found = true;
> +			break;
> +		}
> +	}
> +	igt_require_f(non_dsc_mode_found,
> +		      "No non-DSC mode found on %s\n",
> +		      igt_output_name(data->output));
> +
> +
> +	/* Repeatedly force link failure until DSC is required (or link is disabled) */
> +	while (!igt_get_dp_link_retrain_disabled(data->drm_fd, data->output)) {
> +		mon = igt_watch_uevents();
> +
> +		igt_assert_f(force_failure_and_wait(data, data->output,
> +						    LT_FAILURE_REDUCED_CAPS,
> +						    RETRAIN_COUNT, 1.0, 20.0),
> +			     "Forcing DSC fallback timed out\n");
> +
> +		if (igt_get_dp_link_retrain_disabled(data->drm_fd,
> +						     data->output)) {
> +			igt_reset_connectors();
> +			igt_flush_uevents(mon);
> +			return;
> +		}
> +
> +		igt_assert_f(wait_for_hotplug_and_check_bad(data->drm_fd,
> +							    data,
> +							    data->output,
> +							    mon,
> +							    20.0),
> +			     "Didn't get hotplug or link-status=BAD for DSC\n");
> +		igt_flush_uevents(mon);
> +
> +		outputs[output_count++] = data->output;
> +		set_connector_link_status_good(data, outputs, &output_count);
> +		igt_display_commit2(&data->display, COMMIT_ATOMIC);
> +
> +		mode_to_check = igt_output_get_mode(data->output);
> +
> +		if (igt_is_dsc_enabled(data->drm_fd, data->output->name)) {
> +			igt_info("mode %dx%d@%d now requires DSC with link rate %d and lane count %d\n",
> +				 mode_to_check->hdisplay, mode_to_check->vdisplay,
> +				 mode_to_check->vrefresh,
> +				 igt_get_current_link_rate(data->drm_fd, data->output),
> +				 igt_get_current_lane_count(data->drm_fd, data->output));
> +			igt_info("DSC fallback successful on %s\n",
> +				 igt_output_name(data->output));
> +			dsc_fallback_successful = true;
> +			break;
> +		} else {
> +			igt_info("mode %dx%d@%d still doesn't require DSC\n",
> +				 mode_to_check->hdisplay, mode_to_check->vdisplay,
> +				 mode_to_check->vrefresh);
> +		}
> +	}
> +	igt_assert_f(dsc_fallback_successful, "DSC fallback unsuccessful\n");
> +}
> +
> +static bool run_lt_fallback_test(data_t *data)
>   {
>   	bool ran = false;
>   	igt_output_t *output;
> @@ -366,6 +588,43 @@ static bool run_test(data_t *data)
>   	return ran;
>   }
>   
> +static bool run_dsc_sst_fallaback_test(data_t *data)
> +{
> +	bool ran = false;
> +	igt_output_t *output;
> +
> +	if (!is_dsc_supported_by_source(data->drm_fd)) {
> +		igt_info("DSC not supported by source.\n");
> +		return ran;
> +	}
> +
> +	for_each_connected_output(&data->display, output) {
> +		data->output = output;
> +
> +		if (!igt_has_force_link_training_failure_debugfs(data->drm_fd,
> +								 data->output)) {
> +			igt_info("Output %s doesn't support forcing link training.\n",
> +				 igt_output_name(data->output));
> +			continue;
> +		}
> +
> +		if (output->config.connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) {
> +			igt_info("Skipping output %s as it's not DP\n", output->name);
> +			continue;
> +		}
> +
> +		if (!is_dsc_supported_by_sink(data->drm_fd, data->output)) {
> +			igt_info("Skipping output %s as DSC not supported by sink\n",
> +				 igt_output_name(data->output));
> +			continue;
> +		}
> +
> +		ran = true;
> +		test_dsc_sst_fallback(data);
> +	}
> +	return ran;
> +}
> +
>   igt_main
>   {
>   	data_t data = {};
> @@ -381,8 +640,13 @@ igt_main
>   	}
>   
>   	igt_subtest("dp-fallback") {
> -		igt_require_f(run_test(&data),
> -			      "Skipping test as no output found or none supports fallback\n");
> +		igt_require_f(run_lt_fallback_test(&data),
> +			      "Skipping test as no DP output found or none supports forcing link fail\n");
> +	}
> +
> +	igt_subtest("dsc-fallback") {
> +		igt_require_f(run_dsc_sst_fallaback_test(&data),
> +			      "Skipping test: DSC fallback conditions not met.\n");
>   	}
>   
>   	igt_fixture {
> diff --git a/tests/meson.build b/tests/meson.build
> index 2cbd21c2a..dd75976dd 100644
> --- a/tests/meson.build
> +++ b/tests/meson.build
> @@ -367,7 +367,9 @@ extra_sources = {
>   	'kms_chamelium_frames': [ join_paths ('chamelium', 'kms_chamelium_helper.c') ],
>   	'kms_chamelium_hpd': [ join_paths ('chamelium', 'kms_chamelium_helper.c') ],
>   	'kms_dsc': [ join_paths ('intel', 'kms_dsc_helper.c') ],
> -	'kms_dp_linktrain_fallback': [join_paths ('intel', 'kms_mst_helper.c')],
> +	'kms_dp_linktrain_fallback': [
> +           join_paths ('intel', 'kms_mst_helper.c'),
> +           join_paths ('intel', 'kms_dsc_helper.c')],
>   	'kms_psr2_sf':  [ join_paths ('intel', 'kms_dsc_helper.c') ],
>   }
>   

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2025-02-10  9:56 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-01-23  7:36 [PATCH i-g-t 0/3] add dsc-fallback test Kunal Joshi
2025-01-23  7:36 ` [PATCH i-g-t 1/3] tests/intel/kms_mst_helper: Add helper for MST-related functions Kunal Joshi
2025-01-27  7:17   ` Sharma, Swati2
2025-01-27  8:04     ` Joshi, Kunal1
2025-01-23  7:37 ` [PATCH i-g-t 2/3] tests/intel/kms_dp_linktrain_fallback: add dsc-fallback test Kunal Joshi
2025-01-23  7:37 ` [PATCH i-g-t 3/3] HAX: Do not merge Kunal Joshi
2025-01-23  8:22 ` ✗ GitLab.Pipeline: warning for add dsc-fallback test Patchwork
  -- strict thread matches above, loose matches on Subject: below --
2025-01-27  6:29 [PATCH i-g-t 0/3] " Kunal Joshi
2025-01-27  6:29 ` [PATCH i-g-t 2/3] tests/intel/kms_dp_linktrain_fallback: " Kunal Joshi
2025-01-27  9:17   ` Sharma, Swati2
2025-02-10  9:56   ` Nautiyal, Ankit K

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox