[PATCH i-g-t v2 1/3] tests/kms_joiner: Add tests for Ultrajoiner validation

Reddy Guddati, Santhosh santhosh.reddy.guddati at intel.com
Tue Sep 17 05:06:06 UTC 2024


nit, IMO guard the array boundaries against overflow, otherwise overall 
changes LGTM.
Reviewed-by: Santhosh Reddy Guddati <santhosh.reddy.guddati at intel.com>

On 11-09-2024 12:52, Karthik B S wrote:
> Add a subtest to validate basic ultrajoiner modeset and a negative test
> to validate invalid pipe configs during an ultrajoiner modeset.
> 
> Signed-off-by: Karthik B S <karthik.b.s at intel.com>
> ---
>   lib/igt_kms.c                                 |  44 +++++
>   lib/igt_kms.h                                 |   3 +
>   .../intel/{kms_big_joiner.c => kms_joiner.c}  | 150 ++++++++++++++++--
>   tests/meson.build                             |   2 +-
>   4 files changed, 183 insertions(+), 16 deletions(-)
>   rename tests/intel/{kms_big_joiner.c => kms_joiner.c} (74%)
> 
> diff --git a/lib/igt_kms.c b/lib/igt_kms.c
> index dd530dbab..cf453dcfc 100644
> --- a/lib/igt_kms.c
> +++ b/lib/igt_kms.c
> @@ -6347,6 +6347,50 @@ bool bigjoiner_mode_found(int drm_fd, drmModeConnector *connector,
>   	return found;
>   }
>   
> +/**
> + * igt_ultrajoiner_possible:
> + * @mode: libdrm mode
> + * @max_dotclock: Max pixel clock frequency
> + *
> + * Ultrajoiner will come into the picture, when the requested
> + * mode resolution > 10K or mode clock > 2 * max_dotclock.
> + *
> + * Returns: True if mode requires Ultrajoiner, else False.
> + */
> +bool igt_ultrajoiner_possible(drmModeModeInfo *mode, int max_dotclock)
> +{
> +	return (mode->hdisplay > 2 * MAX_HDISPLAY_PER_PIPE ||
> +		mode->clock > 2 * max_dotclock);
> +}
> +
> +/**
> + * Ultrajoiner_mode_found:
> + * @drm_fd: drm file descriptor
> + * @connector: libdrm connector
> + * @max_dot_clock: max dot clock frequency
> + * @mode: libdrm mode to be filled
> + *
> + * Ultrajoiner will come in to the picture when the
> + * resolution > 10K or clock > 2 * max-dot-clock.
> + *
> + * Returns: True if ultra joiner found in connector modes
> + */
> +bool ultrajoiner_mode_found(int drm_fd, drmModeConnector *connector,
> +			  int max_dotclock, drmModeModeInfo *mode)
> +{
> +	bool found = false;
> +
> +	igt_sort_connector_modes(connector, sort_drm_modes_by_res_dsc);
> +	found = igt_ultrajoiner_possible(&connector->modes[0], max_dotclock);
> +	if (!found) {
> +		igt_sort_connector_modes(connector, sort_drm_modes_by_clk_dsc);
> +		found = igt_ultrajoiner_possible(&connector->modes[0], max_dotclock);
> +	}
> +	if (found)
> +		*mode = connector->modes[0];
> +	return found;
> +}
> +
>   /**
>    * igt_has_force_joiner_debugfs
>    * @drmfd: A drm file descriptor
> diff --git a/lib/igt_kms.h b/lib/igt_kms.h
> index 25ba50916..4455632f4 100644
> --- a/lib/igt_kms.h
> +++ b/lib/igt_kms.h
> @@ -1216,6 +1216,9 @@ int igt_get_max_dotclock(int fd);
>   bool igt_bigjoiner_possible(drmModeModeInfo *mode, int max_dotclock);
>   bool bigjoiner_mode_found(int drm_fd, drmModeConnector *connector,
>   			  int max_dotclock, drmModeModeInfo *mode);
> +bool igt_ultrajoiner_possible(drmModeModeInfo *mode, int max_dotclock);
> +bool ultrajoiner_mode_found(int drm_fd, drmModeConnector *connector,
> +			  int max_dotclock, drmModeModeInfo *mode);
>   bool igt_has_force_joiner_debugfs(int drmfd, char *conn_name);
>   bool igt_check_force_joiner_status(int drmfd, char *connector_name);
>   bool igt_check_bigjoiner_support(igt_display_t *display);
> diff --git a/tests/intel/kms_big_joiner.c b/tests/intel/kms_joiner.c
> similarity index 74%
> rename from tests/intel/kms_big_joiner.c
> rename to tests/intel/kms_joiner.c
> index 7c370bc60..633bf51c7 100644
> --- a/tests/intel/kms_big_joiner.c
> +++ b/tests/intel/kms_joiner.c
> @@ -37,13 +37,20 @@
>   #include "igt.h"
>   
>   /**
> - * SUBTEST: invalid-modeset
> + * SUBTEST: invalid-modeset-big-joiner
>    * Description: Verify if the modeset on the adjoining pipe is rejected when
>    *              the pipe is active with a big joiner modeset
>    *
> - * SUBTEST: basic
> + * SUBTEST: invalid-modeset-ultra-joiner
> + * Description: Verify if the modeset on the other pipes are rejected when
> + *              the pipe A is active with ultra joiner modeset
> + *
> + * SUBTEST: basic-big-joiner
>    * Description: Verify the basic modeset on big joiner mode on all pipes
>    *
> + * SUBTEST: basic-ultra-joiner
> + * Description: Verify the basic modeset on ultra joiner mode on all pipes
> + *
>    * SUBTEST: invalid-modeset-force-joiner
>    * Description: Verify if modeset on adjacent pipe is declined when force joiner modeset is active.
>    *		Force joiner applies bigjoiner functionality to non-bigjoiner outputs,
> @@ -54,20 +61,24 @@
>    *		Force joiner applies bigjoiner functionality to non-bigjoiner outputs thus,
>    *		the test exclusively targets non-bigjoiner outputs.
>    */
> -IGT_TEST_DESCRIPTION("Test big joiner / force joiner");
> +IGT_TEST_DESCRIPTION("Test joiner / force joiner");
>   
>   #define INVALID_TEST_OUTPUT 2
>   
>   typedef struct {
>   	int drm_fd;
>   	int big_joiner_output_count;
> +	int ultra_joiner_output_count;
>   	int non_big_joiner_output_count;
> +	int non_ultra_joiner_output_count;
>   	int mixed_output_count;
>   	int output_count;
>   	int n_pipes;
>   	uint32_t master_pipes;
>   	igt_output_t *big_joiner_output[IGT_MAX_PIPES];
> +	igt_output_t *ultra_joiner_output[IGT_MAX_PIPES];
>   	igt_output_t *non_big_joiner_output[IGT_MAX_PIPES];
> +	igt_output_t *non_ultra_joiner_output[IGT_MAX_PIPES];
>   	igt_output_t *mixed_output[IGT_MAX_PIPES];
>   	enum pipe pipe_seq[IGT_MAX_PIPES];
>   	igt_display_t display;
> @@ -286,6 +297,81 @@ static void test_joiner_on_last_pipe(data_t *data, bool force_joiner)
>   	}
>   }
>   
> +static void test_ultra_joiner(data_t *data, bool invalid_pipe, bool two_display)
> +{
> +	int i, j, k, ret;
> +	igt_output_t *output, *non_ultra_joiner_output;
> +	igt_plane_t *primary;
> +	igt_output_t **outputs;
> +	igt_fb_t fb;
> +	drmModeModeInfo mode;
> +
> +	outputs = data->ultra_joiner_output;
> +	igt_display_reset(&data->display);
> +	igt_display_commit2(&data->display, COMMIT_ATOMIC);
> +
> +	for (i = 0; i < data->ultra_joiner_output_count; i++) {
> +		output = outputs[i];
> +		igt_require(ultrajoiner_mode_found(data->drm_fd, output->config.connector, max_dotclock, &mode));
> +		igt_output_override_mode(output, &mode);
> +		for (j = 0; j < data->n_pipes; j++) {
> +			/* Ultra joiner is only valid on PIPE_A */
> +			if (invalid_pipe && j == PIPE_A)
> +				continue;
> +			if (!invalid_pipe && j != PIPE_A)
> +				continue;
> +			if (two_display && j != PIPE_A)
> +				continue;
> +
> +			igt_output_set_pipe(output, data->pipe_seq[j]);
> +
> +			primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> +			igt_create_pattern_fb(data->drm_fd, mode.hdisplay, mode.vdisplay, DRM_FORMAT_XRGB8888,
> +					      DRM_FORMAT_MOD_LINEAR, &fb);
> +			igt_plane_set_fb(primary, &fb);
> +
> +			if (invalid_pipe)
> +				ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
> +			else
> +				igt_display_commit2(&data->display, COMMIT_ATOMIC);
> +
> +			if (two_display) {
> +				for_each_connected_output(&data->display, non_ultra_joiner_output) {
> +					if (output->id != non_ultra_joiner_output->id) {
> +						for (k = 1; k < data->n_pipes; k++) {
> +							igt_plane_t *plane;
> +							drmModeModeInfo *mode1;
> +
> +							mode1 = igt_output_get_mode(non_ultra_joiner_output);
> +
> +							igt_output_set_pipe(non_ultra_joiner_output, data->pipe_seq[k]);
> +							plane = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> +
> +							igt_plane_set_fb(plane, &fb);
> +							igt_fb_set_size(&fb, plane, mode1->hdisplay, mode1->vdisplay);
> +							igt_plane_set_size(plane, mode1->hdisplay, mode1->vdisplay);
> +
> +							ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
> +
> +							igt_plane_set_fb(plane, NULL);
> +							igt_assert_f(ret != 0, "Commit expected to fail on second display\n");
> +						}
> +						/* Validation with one output is sufficient */
> +						break;
> +					}
> +				}
> +			}
> +
> +			igt_display_reset(&data->display);
> +			igt_plane_set_fb(primary, NULL);
> +			igt_remove_fb(data->drm_fd, &fb);
> +
> +			if (invalid_pipe)
> +				igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
> +		}
> +	}
> +}
> +
>   igt_main
>   {
>   	bool force_joiner_supported;
> @@ -297,7 +383,9 @@ igt_main
>   	igt_fixture {
>   		force_joiner_supported = false;
>   		data.big_joiner_output_count = 0;
> +		data.ultra_joiner_output_count = 0;
>   		data.non_big_joiner_output_count = 0;
> +		data.non_ultra_joiner_output_count = 0;
>   		data.mixed_output_count = 0;
>   		data.output_count = 0;
>   		j = 0;
> @@ -310,24 +398,31 @@ igt_main
>   		max_dotclock = igt_get_max_dotclock(data.drm_fd);
>   
>   		for_each_connected_output(&data.display, output) {
> -			bool found = false;
> +			bool ultrajoiner_found = false, bigjoiner_found = false;
>   			drmModeConnector *connector = output->config.connector;
>   
>   			/*
>   			 * Bigjoiner will come in to the picture when the
>   			 * resolution > 5K or clock > max-dot-clock.
> +			 * Ultrajoiner will come in to the picture when the
> +			 * resolution > 10K or clock > 2 * max-dot-clock.
>   			 */
> -			found = bigjoiner_mode_found(data.drm_fd, connector, max_dotclock, &mode);
> +			bigjoiner_found = bigjoiner_mode_found(data.drm_fd, connector, max_dotclock, &mode);
> +			ultrajoiner_found = ultrajoiner_mode_found(data.drm_fd, connector, max_dotclock, &mode);
>   
> -			if (found) {
> +			if (igt_has_force_joiner_debugfs(data.drm_fd, output->name))
> +				force_joiner_supported = true;
> +
> +			if (ultrajoiner_found)
> +				data.ultra_joiner_output[data.ultra_joiner_output_count++] = output;
> +			else if (force_joiner_supported)
> +				data.non_ultra_joiner_output[data.non_ultra_joiner_output_count++] = output;
     >> nit, IMO guard the array boundaries against overflow, otherwise 
overall changes LGTM.
	
if (ultrajoiner_found && data.ultra_joiner_output_count < IGT_MAX_PIPES)
		data.ultra_joiner_output[data.ultra_joiner_output_count++] = output;
			else if (force_joiner_supported && data.non_ultra_joiner_output_count 
< IGT_MAX_PIPES)
				data.non_ultra_joiner_output[data.non_ultra_joiner_output_count++] = 
output;
> +
> +			if (bigjoiner_found)
>   				data.big_joiner_output[data.big_joiner_output_count++] = output;
> -				igt_output_override_mode(output, &mode);
> -			} else {
> -				if (igt_has_force_joiner_debugfs(data.drm_fd, output->name)) {
> -					force_joiner_supported = true;
> -					data.non_big_joiner_output[data.non_big_joiner_output_count++] = output;
> -				}
> -			}
> +			else if (force_joiner_supported)
> +				data.non_big_joiner_output[data.non_big_joiner_output_count++] = output;
> +
>   			data.output_count++;
>   		}
>   		if (data.big_joiner_output_count == 1 && data.non_big_joiner_output_count >= 1) {
> @@ -337,6 +432,7 @@ igt_main
>   			data.mixed_output[data.mixed_output_count++] = data.big_joiner_output[0];
>   			data.mixed_output[data.mixed_output_count++] = data.non_big_joiner_output[0];
>   		}
> +
>   		data.n_pipes = 0;
>   		for_each_pipe(&data.display, i) {
>   			data.n_pipes++;
> @@ -346,7 +442,7 @@ igt_main
>   	}
>   
>   	igt_describe("Verify the basic modeset on big joiner mode on all pipes");
> -	igt_subtest_with_dynamic("basic") {
> +	igt_subtest_with_dynamic("basic-big-joiner") {
>   			igt_require_f(data.big_joiner_output_count > 0,
>   				      "No bigjoiner output found\n");
>   			igt_require_f(data.n_pipes > 1,
> @@ -358,9 +454,19 @@ igt_main
>   					test_multi_joiner(&data, data.big_joiner_output_count, false);
>   	}
>   
> +	igt_describe("Verify the basic modeset on ultra joiner mode on all pipes");
> +	igt_subtest_with_dynamic("basic-ultra-joiner") {
> +			igt_require_f(data.ultra_joiner_output_count > 0,
> +				      "No ultrajoiner output found\n");
> +			igt_require_f(data.n_pipes > 3,
> +				      "Minimum 4 pipes required\n");
> +			igt_dynamic_f("single-joiner")
> +				test_ultra_joiner(&data, false, false);
> +	}
> +
>   	igt_describe("Verify if the modeset on the adjoining pipe is rejected "
>   		     "when the pipe is active with a big joiner modeset");
> -	igt_subtest_with_dynamic("invalid-modeset") {
> +	igt_subtest_with_dynamic("invalid-modeset-big-joiner") {
>   		igt_require_f(data.big_joiner_output_count > 0, "Non big joiner output not found\n");
>   		igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
>   		if (data.big_joiner_output_count >= 1)
> @@ -374,6 +480,20 @@ igt_main
>   				test_invalid_modeset_two_joiner(&data, true, false);
>   	}
>   
> +	igt_describe("Verify if the modeset on the other pipes are rejected "
> +		     "when the pipe A is active with a ultra joiner modeset");
> +	igt_subtest_with_dynamic("invalid-modeset-ultra-joiner") {
> +		igt_require_f(data.ultra_joiner_output_count > 0, "Ultra joiner output not found\n");
> +		igt_require_f(data.n_pipes > 3, "Minimum of 4 pipes are required\n");
> +
> +		igt_dynamic_f("ultra_joiner_on_invalid_pipe")
> +			test_ultra_joiner(&data, true, false);
> +		if (data.non_ultra_joiner_output_count > 0) {
> +			igt_dynamic_f("2x")
> +				test_ultra_joiner(&data, false, true);
> +		}
> +	}
> +
>   	igt_describe("Verify the basic modeset on big joiner mode on all pipes");
>   	igt_subtest_with_dynamic("basic-force-joiner") {
>   		igt_require_f(force_joiner_supported,
> diff --git a/tests/meson.build b/tests/meson.build
> index 00556c9d6..c8cba1b9a 100644
> --- a/tests/meson.build
> +++ b/tests/meson.build
> @@ -242,7 +242,6 @@ intel_i915_progs = [
>   
>   intel_kms_progs = [
>   	'kms_big_fb',
> -	'kms_big_joiner' ,
>   	'kms_busy',
>   	'kms_ccs',
>   	'kms_cdclk',
> @@ -255,6 +254,7 @@ intel_kms_progs = [
>   	'kms_flip_scaled_crc',
>   	'kms_flip_tiling',
>   	'kms_frontbuffer_tracking',
> +	'kms_joiner',
>   	'kms_legacy_colorkey',
>   	'kms_mmap_write_crc',
>   	'kms_pipe_b_c_ivb',


More information about the igt-dev mailing list