[PATCH i-g-t 09/10] tests/intel/kms_dp_fallback: add test for validating fallback
Kunal Joshi
kunal1.joshi at intel.com
Tue Jul 30 21:13:40 UTC 2024
add fallback test which tries to validate fallback by
reducing link rate / lane count, until retrain is disabled
or the lowest mode bw requirements are met.
v2: add test for mst (imre)
refresh mode list (imre)
monitor got hotplugs (imre)
check link parameter are reduced (imre)
Signed-off-by: Kunal Joshi <kunal1.joshi at intel.com>
---
tests/intel/kms_dp_fallback.c | 361 ++++++++++++++++++++++++++++++++++
tests/meson.build | 1 +
2 files changed, 362 insertions(+)
create mode 100644 tests/intel/kms_dp_fallback.c
diff --git a/tests/intel/kms_dp_fallback.c b/tests/intel/kms_dp_fallback.c
new file mode 100644
index 000000000..0a74bfc58
--- /dev/null
+++ b/tests/intel/kms_dp_fallback.c
@@ -0,0 +1,361 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2024 Intel Corporation
+ */
+
+/**
+ * TEST: kms dp fallback
+ * Category: Display
+ * Description: Test link training fallback for DP connectors
+ * Driver requirement: i915, xe
+ * Functionality: link training
+ * Mega feature: General Display Features
+ * Test category: functionality test
+ */
+
+#include <sys/types.h>
+
+#include "igt.h"
+#include "igt_psr.h"
+
+/**
+ * SUBTEST: dp-fallback
+ * Description: Test fallback on DP connectors
+ *
+ * SUBTEST: mst-fallback
+ * Description: Test fallback on DP MST connectors
+ *
+ * SUBTEST: uhbr-fallback
+ * Description: Test fallback on DP connectors with uhbr link rate
+ */
+
+enum tests {
+ TEST_EDP_FALLBACK,
+ TEST_DP_FALLBACK,
+ TEST_MST_FALLBACK,
+ TEST_UHBR_FALLBACK,
+ MAX_TESTS,
+};
+
+typedef struct {
+ int drm_fd;
+ igt_display_t display;
+ drmModeModeInfo *mode;
+ igt_output_t *output;
+ enum pipe pipe;
+ struct igt_fb fb;
+ struct igt_plane *primary;
+ enum tests test;
+ int n_pipes;
+} data_t;
+
+IGT_TEST_DESCRIPTION("Test link training fallback for DP connectors");
+
+#define BITS_PER_PIXEL 24
+#define ENCODING_OVERHEAD_8b_10b 0.8
+#define ENCODING_OVERHEAD_128b_132b 0.9723
+
+static const char *str_link_rate(enum dp_link_rate link_rate)
+{
+ switch (link_rate) {
+ case DP_LINK_RATE_162000:
+ return "1.62 Gbps";
+ case DP_LINK_RATE_216000:
+ return "2.16 Gbps";
+ case DP_LINK_RATE_243000:
+ return "2.43 Gbps";
+ case DP_LINK_RATE_270000:
+ return "2.70 Gbps";
+ case DP_LINK_RATE_324000:
+ return "3.24 Gbps";
+ case DP_LINK_RATE_432000:
+ return "4.32 Gbps";
+ case DP_LINK_RATE_540000:
+ return "5.40 Gbps";
+ case DP_LINK_RATE_675000:
+ return "6.75 Gbps";
+ case DP_LINK_RATE_810000:
+ return "8.10 Gbps";
+ case DP_LINK_RATE_1000000:
+ return "10.00 Gbps";
+ case DP_LINK_RATE_1350000:
+ return "13.50 Gbps";
+ case DP_LINK_RATE_2000000:
+ return "20.00 Gbps";
+ default:
+ igt_assert_f(0, "Invalid link rate %d\n", link_rate);
+ }
+}
+
+static const char *str_lane_count(enum dp_lane_count lane_count)
+{
+ switch (lane_count) {
+ case DP_LANE_COUNT_1:
+ return "1";
+ case DP_LANE_COUNT_2:
+ return "2";
+ case DP_LANE_COUNT_4:
+ return "4";
+ default:
+ igt_assert_f(0, "Invalid lane count %d\n", lane_count);
+ }
+}
+
+static void find_mst_outputs(int drm_fd, data_t *data, igt_output_t *output,
+ igt_output_t **mst_outputs, int *num_mst_outputs)
+{
+ bool is_output_mst;
+ uint64_t path_blob_id;
+ igt_output_t *connector_output;
+ drmModePropertyPtr path_prop = NULL;
+ drmModePropertyPtr connector_path_prop = NULL;
+
+ igt_assert_f(output, "Invalid output\n");
+
+ /*
+ * Check if given output is MST by checking if it has PATH property
+ */
+ is_output_mst = kmstest_get_property(drm_fd,
+ output->config.connector->connector_id,
+ DRM_MODE_OBJECT_CONNECTOR, "PATH", NULL,
+ &path_blob_id, &path_prop);
+
+ if (!is_output_mst)
+ return;
+
+ /*
+ * 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 (connector_output->config.connector == output->config.connector)
+ continue;
+
+ connector_path_prop = NULL;
+
+ kmstest_get_property(drm_fd,
+ connector_output->config.connector->connector_id,
+ DRM_MODE_OBJECT_CONNECTOR, "PATH", NULL,
+ &path_blob_id, &connector_path_prop);
+
+ if (connector_path_prop && path_prop &&
+ connector_path_prop->prop_id == path_prop->prop_id)
+ mst_outputs[(*num_mst_outputs)++] = connector_output;
+
+ if (connector_path_prop)
+ drmModeFreeProperty(connector_path_prop);
+ }
+ if (path_prop)
+ drmModeFreeProperty(path_prop);
+}
+
+static bool is_retrain_disabled(data_t *data)
+{
+ return igt_get_dp_link_retrain_disabled(data->drm_fd, data->output);
+}
+
+static void test_mst_fallback(data_t *data, igt_output_t **mst_outputs, int *no_of_mst_outputs)
+{
+ int i;
+ enum dp_link_rate link_rate, prev_link_rate, curr_link_rate;
+ enum dp_lane_count lane_count, prev_lane_count, curr_lane_count;
+ struct udev_monitor *mon;
+ igt_output_t *output[*no_of_mst_outputs];
+ drmModeModeInfo *mode[*no_of_mst_outputs];
+ igt_plane_t *primary[*no_of_mst_outputs];
+ struct igt_fb fb[*no_of_mst_outputs];
+
+ link_rate = igt_get_dp_max_link_rate(data->drm_fd, data->output);
+ lane_count = igt_get_dp_max_lane_count(data->drm_fd, data->output);
+ prev_link_rate = link_rate;
+ prev_lane_count = lane_count;
+
+
+ while (!is_retrain_disabled(data)) {
+
+ for (i = 0; i < *no_of_mst_outputs; i++) {
+ if (i > data->n_pipes)
+ break;
+
+ output[i] = mst_outputs[i];
+ output[i]->force_reprobe = true;
+ igt_output_refresh(output[i]);
+ mode[i] = &output[i]->config.connector->modes[0];
+ igt_debug("updated output %s mode: %dx%d@%d\n", output[i]->name, mode[i]->hdisplay, mode[i]->vdisplay, mode[i]->vrefresh);
+ igt_create_fb(data->drm_fd, mode[i]->hdisplay, mode[i]->vdisplay, DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR, &fb[i]);
+ igt_output_set_pipe(output[i], i);
+ primary[i] = igt_output_get_plane_type(output[i], DRM_PLANE_TYPE_PRIMARY);
+ igt_plane_set_fb(primary[i], &fb[i]);
+ }
+
+ igt_display_commit2(&data->display, COMMIT_ATOMIC);
+ mon = igt_watch_uevents();
+
+ igt_debug("forcing link training failure and retraining\n");
+ kmstest_force_connector_link_training_failure(data->drm_fd, data->output->config.connector, 2);
+
+ while (igt_get_dp_pending_lt_failures(data->drm_fd, data->output) > 0)
+ kmstest_force_connector_retrain(data->drm_fd, data->output->config.connector, 1);
+
+ igt_assert_f(igt_hotplug_detected(mon, 20) || is_retrain_disabled(data),
+ "Didn't get hotplug for force link training failure\n");
+ igt_flush_uevents(mon);
+
+ curr_link_rate = igt_get_dp_link_rate_set_for_output(data->drm_fd, data->output);
+ curr_lane_count = igt_get_dp_lane_count_set_for_output(data->drm_fd, data->output);
+ igt_info("Current link rate : %s, lane count : %s\n",
+ str_link_rate(curr_link_rate), str_lane_count(curr_lane_count));
+ igt_assert_f(curr_link_rate < prev_link_rate || curr_lane_count < prev_lane_count,
+ "Fallback failed\n");
+ }
+
+ kmstest_force_connector_link_rate(data->drm_fd, data->output->config.connector, link_rate);
+ kmstest_force_connector_lane_count(data->drm_fd, data->output->config.connector, lane_count);
+ kmstest_force_connector_retrain(data->drm_fd, data->output->config.connector, 1);
+ igt_reset_connectors();
+}
+
+static void test_dp_fallback(data_t *data)
+{
+ struct udev_monitor *mon;
+ enum dp_link_rate link_rate, prev_link_rate, curr_link_rate;
+ enum dp_lane_count lane_count, prev_lane_count, curr_lane_count;
+
+ link_rate = igt_get_dp_max_link_rate(data->drm_fd, data->output);
+ lane_count = igt_get_dp_max_lane_count(data->drm_fd, data->output);
+ prev_link_rate = link_rate;
+ prev_lane_count = lane_count;
+
+ for_each_pipe(&data->display, data->pipe) {
+
+ igt_dynamic_f("%s-pipe-%s", igt_output_name(data->output),
+ kmstest_pipe_name(data->pipe)) {
+
+ if (data->test == TEST_UHBR_FALLBACK)
+ igt_require_f(link_rate > DP_LINK_RATE_810000,
+ "%s is doesn't have UHBR rate\n", data->output->name);
+
+ igt_display_reset(&data->display);
+
+ while (!is_retrain_disabled(data)) {
+
+ /*
+ * Start with default mode and fallback till we reach minimum link rate and lane count
+ */
+ data->output->force_reprobe = true;
+ igt_output_refresh(data->output);
+ data->mode = &data->output->config.connector->modes[0];
+ igt_debug("mode: %dx%d@%d\n",
+ data->mode->hdisplay, data->mode->vdisplay,
+ data->mode->vrefresh);
+ igt_create_pattern_fb(data->drm_fd, data->mode->hdisplay,
+ data->mode->vdisplay, DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_MOD_LINEAR, &data->fb);
+ 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);
+ igt_display_commit2(&data->display, COMMIT_ATOMIC);
+
+ mon = igt_watch_uevents();
+
+ igt_debug("forcing link training failure and retraining\n");
+ kmstest_force_connector_link_training_failure(data->drm_fd, data->output->config.connector, 2);
+
+ while (igt_get_dp_pending_lt_failures(data->drm_fd, data->output) > 0)
+ kmstest_force_connector_retrain(data->drm_fd, data->output->config.connector, 1);
+
+ igt_assert_f(igt_hotplug_detected(mon, 20) || is_retrain_disabled(data),
+ "Didn't get hotplug for force link training failure\n");
+ igt_flush_uevents(mon);
+
+ curr_link_rate = igt_get_dp_link_rate_set_for_output(data->drm_fd, data->output);
+ curr_lane_count = igt_get_dp_lane_count_set_for_output(data->drm_fd, data->output);
+ igt_info("Current link rate : %s, lane count : %s\n",
+ str_link_rate(curr_link_rate), str_lane_count(curr_lane_count));
+ igt_assert_f(curr_link_rate < prev_link_rate || curr_lane_count < prev_lane_count,
+ "Fallback failed\n");
+ }
+ kmstest_force_connector_link_rate(data->drm_fd, data->output->config.connector, link_rate);
+ kmstest_force_connector_lane_count(data->drm_fd, data->output->config.connector, lane_count);
+ kmstest_force_connector_retrain(data->drm_fd, data->output->config.connector, 1);
+ igt_reset_connectors();
+ }
+ }
+}
+
+igt_main
+{
+ data_t data = {};
+ igt_output_t *output;
+ enum pipe pipe;
+
+ igt_fixture {
+ data.drm_fd = drm_open_driver_master(DRIVER_INTEL);
+ data.n_pipes = 0;
+ kmstest_set_vt_graphics_mode();
+ igt_display_require(&data.display, data.drm_fd);
+
+ for_each_pipe(&data.display, pipe)
+ data.n_pipes++;
+
+ }
+
+ igt_describe_f("Test DP fallback");
+ igt_subtest_with_dynamic("dp-fallback")
+ {
+ data.test = TEST_DP_FALLBACK;
+ for_each_connected_output(&data.display, output) {
+ /* Skip if output is not DP or if it's mst*/
+ if (output->config.connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) {
+ igt_info("Skipping output %s as it's not DP\n", output->name);
+ continue;
+ }
+ data.output = output;
+ test_dp_fallback(&data);
+ }
+ }
+
+ igt_describe_f("Test UHBR fallback");
+ igt_subtest_with_dynamic_f("uhbr-fallback")
+ {
+ data.test = TEST_UHBR_FALLBACK;
+ for_each_connected_output(&data.display, output) {
+ /* Skip if output is not DP or if it's mst*/
+ if (output->config.connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) {
+ igt_info("Skipping output %s as it's not DP\n", output->name);
+ continue;
+ }
+ data.output = output;
+ test_dp_fallback(&data);
+ }
+ }
+
+ igt_describe_f("MST Fallback");
+ igt_subtest_with_dynamic("mst-fallback")
+ {
+ int num_mst_outputs;
+ igt_output_t **mst_outputs;
+
+ for_each_connected_output(&data.display, output) {
+
+ if (!igt_check_output_is_dp_mst(output)) {
+ igt_info("Skipping output %s as its non mst\n", output->name);
+ continue;
+ }
+
+ num_mst_outputs = 0;
+ mst_outputs = malloc(sizeof(igt_output_t *) * data.n_pipes);
+ data.output = output;
+ mst_outputs[num_mst_outputs++] = output;
+ find_mst_outputs(data.drm_fd, &data, data.output, mst_outputs, &num_mst_outputs);
+ igt_dynamic_f("%s", igt_output_name(data.output))
+ test_mst_fallback(&data, mst_outputs, &num_mst_outputs);
+ }
+ }
+
+ igt_fixture {
+ igt_display_fini(&data.display);
+ drm_close_driver(data.drm_fd);
+ }
+}
diff --git a/tests/meson.build b/tests/meson.build
index e649466be..23c453170 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -247,6 +247,7 @@ intel_kms_progs = [
'kms_ccs',
'kms_cdclk',
'kms_dirtyfb',
+ 'kms_dp_fallback',
'kms_draw_crc',
'kms_dsc',
'kms_fb_coherency',
--
2.43.0
More information about the igt-dev
mailing list