Igt-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Alex Hung <alex.hung@amd.com>
To: Ray Wu <ray.wu@amd.com>, igt-dev@lists.freedesktop.org
Cc: sunpeng.li@amd.com, chiahsuan.chung@amd.com
Subject: Re: [PATCH i-g-t 2/2] tests/amdgpu/amd_replay: add Replay Rate Control IGT test
Date: Tue, 12 May 2026 09:40:03 -0600	[thread overview]
Message-ID: <ab6fa4a7-1c27-4d35-8df7-cbbed88f30e4@amd.com> (raw)
In-Reply-To: <20260512080213.3457271-3-ray.wu@amd.com>



On 5/12/26 01:59, Ray Wu wrote:
> [Why]
> Panel Replay rate control lowers the panel refresh rate while the
> screen is static by extending coasting vtotal, and restores it when
> the screen becomes live again. There is currently no IGT coverage for
> this behaviour.
> 
> [How]
> Add two helpers in lib/igt_amd:
> 
>    - igt_amd_replay_support_rate_control(): true when the connector's
>      replay_capability advertises "Rate control support: yes".
>    - igt_amd_read_replay_coasting_vtotal(): reads replay_coasting_vtotal;
>      returns 0 on success or -errno on failure.
> 
> Add a "replay_rate_control" subtest that engages Panel Replay via page
> flips, samples the coasting vtotal in static and live modes, and
> asserts that the static value is strictly greater than the live value.
> Skips cleanly when eDP, Panel Replay, or rate control support is
> missing.
> 
> Signed-off-by: Ray Wu <ray.wu@amd.com>
> ---
>   lib/igt_amd.c             | 93 +++++++++++++++++++++++++++++++++++++++
>   lib/igt_amd.h             |  3 ++
>   tests/amdgpu/amd_replay.c | 86 ++++++++++++++++++++++++++++++++++++
>   3 files changed, 182 insertions(+)
> 
> diff --git a/lib/igt_amd.c b/lib/igt_amd.c
> index a97adad43..89474eb15 100644
> --- a/lib/igt_amd.c
> +++ b/lib/igt_amd.c
> @@ -20,7 +20,9 @@
>    * OTHER DEALINGS IN THE SOFTWARE.
>    */
>   
> +#include <errno.h>
>   #include <fcntl.h>
> +#include <string.h>
>   #include <sys/stat.h>
>   
>   #include "igt_amd.h"
> @@ -1082,6 +1084,40 @@ bool igt_amd_replay_support_drv(int drm_fd, char *connector_name)
>   	return strstr(buf, "Driver support: yes") && strstr(buf, "Config support: yes");
>   }
>   
> +/**
> + * igt_amd_replay_support_rate_control: check if Panel Replay rate control is supported
> + * @drm_fd: DRM file descriptor
> + * @connector_name: The connector's name, on which we're reading the status
> + *
> + * Return:
> + *   true  - "Rate control support: yes" found in replay_capability
> + *   false - rate control not supported, field not present (older kernel),
> + *           or any read/debugfs error
> + */
> +bool igt_amd_replay_support_rate_control(int drm_fd, char *connector_name)
> +{
> +	char buf[128];
> +	int ret;
> +	int fd;
> +
> +	fd = igt_debugfs_connector_dir(drm_fd, connector_name, O_RDONLY);
> +	if (fd < 0) {
> +		igt_info("output %s: debugfs not found\n", connector_name);
> +
> +		return false;
> +	}
> +
> +	ret = igt_debugfs_simple_read(fd, DEBUGFS_EDP_REPLAY_CAP, buf, sizeof(buf));
> +	igt_assert_f(ret >= 0, "Reading %s for connector %s failed.\n",
> +		     DEBUGFS_EDP_REPLAY_CAP, connector_name);
> +	close(fd);
igt_assert_f can terminate this function early and close(fd) will not be 
run. Let's move close(fd) up.

> +
> +	if (ret < 1)
> +		return false;
> +
> +	return strstr(buf, "Rate control support: yes");
> +}
> +
>   /**
>    * igt_amd_output_has_replay_state: check if eDP connector has replay_state debugfs entry
>    * @drm_fd: DRM file descriptor
> @@ -1177,6 +1213,63 @@ enum replay_state igt_amd_read_replay_state(int drm_fd, char *connector_name)
>   	return convert_replay_state(raw_state);
>   }
>   
> +/**
> + * @brief Read Panel Replay current coasting vtotal from debugfs interface
> + * @param drm_fd DRM file descriptor
> + * @param connector_name The connector's name, on which we're reading the status
> + * @param vtotal Out: parsed vtotal value (only valid when return value is 0)
> + *
> + * Reads /sys/kernel/debug/dri/<N>/<connector>/replay_current_coasting_vtotal,
> + * which contains a single decimal number (e.g. "4938").
> + *
> + * Return:
> + *   0       on success, *vtotal contains the parsed value
> + *  -errno   on failure. Errors from the underlying igt debugfs helpers are
> + *           passed through; -EINVAL is returned when arguments are invalid
> + *           or the file content cannot be parsed.
> + */
> +int igt_amd_read_replay_coasting_vtotal(int drm_fd, char *connector_name,
> +					uint32_t *vtotal)
> +{
> +	char buf[32] = {0};
> +	int fd, ret;
> +	unsigned long parsed;
> +	char *endp;
> +
> +	if (!vtotal)
> +		return -EINVAL;
> +
> +	fd = igt_debugfs_connector_dir(drm_fd, connector_name, O_RDONLY);
> +	if (fd < 0) {
> +		ret = -errno;
> +		igt_info("Couldn't open connector %s debugfs directory (%s)\n",
> +			 connector_name, strerror(-ret));
> +		return ret;
> +	}
> +
> +	ret = igt_debugfs_simple_read(fd, DEBUGFS_EDP_REPLAY_COASTING_VTOTAL,
> +				      buf, sizeof(buf) - 1);
> +	close(fd);
> +
> +	if (ret < 1) {
> +		igt_info("Reading %s for connector %s failed (%s)\n",
> +			 DEBUGFS_EDP_REPLAY_COASTING_VTOTAL, connector_name,
> +			 ret < 0 ? strerror(-ret) : "empty");
> +		return ret < 0 ? ret : -ENODATA;
> +	}
> +
> +	parsed = strtoul(buf, &endp, 10);
> +	if (endp == buf) {
> +		igt_info("%s for connector %s: unparseable value '%s'\n",
> +			 DEBUGFS_EDP_REPLAY_COASTING_VTOTAL, connector_name,
> +			 buf);
> +		return -EINVAL;
> +	}
> +
> +	*vtotal = (uint32_t)parsed;
> +	return 0;
> +}
> +
>   /**
>    * igt_amd_output_has_psr_cap: check if eDP connector has psr_capability debugfs entry
>    * @drm_fd: DRM file descriptor
> diff --git a/lib/igt_amd.h b/lib/igt_amd.h
> index a45122b68..7f11e1d38 100644
> --- a/lib/igt_amd.h
> +++ b/lib/igt_amd.h
> @@ -49,6 +49,7 @@
>   #define MULTIPLIER_TO_LR 270000
>   #define DEBUGFS_EDP_REPLAY_CAP "replay_capability"
>   #define DEBUGFS_EDP_REPLAY_STATE "replay_state"
> +#define DEBUGFS_EDP_REPLAY_COASTING_VTOTAL "replay_coasting_vtotal"
>   #define DEBUGFS_EDP_PSR_CAP	"psr_capability"
>   #define DEBUGFS_EDP_PSR_STATE	"psr_state"
>   #define DEBUGFS_ALLOW_EDP_HOTPLUG_DETECT "allow_edp_hotplug_detection"
> @@ -227,6 +228,8 @@ bool igt_amd_output_has_ilr_setting(int drm_fd, char *connector_name);
>   bool igt_amd_output_has_replay_cap(int drm_fd, char *connector_name);
>   bool igt_amd_replay_support_sink(int drm_fd, char *connector_name);
>   bool igt_amd_replay_support_drv(int drm_fd, char *connector_name);
> +bool igt_amd_replay_support_rate_control(int drm_fd, char *connector_name);
> +int igt_amd_read_replay_coasting_vtotal(int drm_fd, char *connector_name, uint32_t *vtotal);
>   bool igt_amd_output_has_replay_state(int drm_fd, char *connector_name);
>   enum replay_state igt_amd_read_replay_state(int drm_fd, char *connector_name);
>   bool igt_amd_output_has_psr_cap(int drm_fd, char *connector_name);
> diff --git a/tests/amdgpu/amd_replay.c b/tests/amdgpu/amd_replay.c
> index 4b795f5ba..fd0b01f05 100644
> --- a/tests/amdgpu/amd_replay.c
> +++ b/tests/amdgpu/amd_replay.c
> @@ -5,6 +5,7 @@
>   
>   #include <dirent.h>
>   #include <fcntl.h>
> +#include <string.h>
>   
>   #include "igt_amd.h"
>   
> @@ -397,6 +398,88 @@ static void run_check_replay_suspend(struct test_data *data)
>   	test_fini(data);
>   }
>   
> +/*
> + * Verify replay rate control: when the screen is static, coasting vtotal should be
> + * extended to lower RR; under live mode, coasting vtotal should drop back.
> + *
> + *     coasting_vtotal_in_static >= coasting_vtotal_in_live

Should this be "static_coasting_vtotal > live_coasting_vtotal"?

> + *
> + */
> +static void run_check_replay_rate_control(struct test_data *data)
> +{
> +	int edp_idx;
> +	igt_output_t *output;
> +	uint32_t static_coasting_vtotal = 0;
> +	uint32_t live_coasting_vtotal = 0;
> +	int ret;
> +
> +	test_init(data);
> +
> +	edp_idx = check_conn_type(data, DRM_MODE_CONNECTOR_eDP);
> +	igt_skip_on_f(edp_idx == -1, "no eDP connector found\n");
> +
> +	/* check if eDP supports Panel Replay. */
> +	igt_skip_on(!replay_mode_supported(data));
> +
> +	igt_skip_on_f(!igt_amd_replay_support_rate_control(data->fd,
> +							   data->output->name),
> +		      "Replay rate control not supported; skip test\n");
> +
> +	for_each_connected_output(&data->display, output) {
> +		if (output->config.connector->connector_type != DRM_MODE_CONNECTOR_eDP)
> +			continue;
> +
> +		igt_create_color_fb(data->fd, data->mode->hdisplay,
> +				    data->mode->vdisplay, DRM_FORMAT_XRGB8888, 0,
> +				    0.6, 0.6, 0.6, &data->ref_fb);
> +		igt_create_color_fb(data->fd, data->mode->hdisplay,
> +				    data->mode->vdisplay, DRM_FORMAT_XRGB8888, 0,
> +				    0.0, 0.4, 0.14, &data->ref_fb2);
> +
> +		igt_plane_set_fb(data->primary, &data->ref_fb);
> +		igt_display_commit_atomic(&data->display,
> +					  DRM_MODE_ATOMIC_ALLOW_MODESET, 0);
> +		data->flip_fb = &data->ref_fb;
> +
> +		drmModePageFlip(data->fd, output->config.crtc->crtc_id,
> +				data->flip_fb->fb_id, DRM_MODE_PAGE_FLIP_EVENT, NULL);

drmModePageFlip's return needs to be checked.

> +		kmstest_wait_for_pageflip(data->fd);
> +
> +		/* Do some page flips and let replay enable */
> +		page_flip_test(data, output, TEST_MODE_FLIP_ONLY,
> +			       FLIP_FRAME_BEFORE_TEST);
> +
> +		/* Panel Replay state takes time to settle on static screen */
> +		sleep(1);
> +		ret = igt_amd_read_replay_coasting_vtotal(data->fd,
> +							  output->name,
> +							  &static_coasting_vtotal);
> +		igt_assert_f(ret == 0,
> +			     "failed to read static-mode coasting vtotal: %s\n",
> +			     strerror(-ret));
> +
> +		/* Drive page flips to put replay into live mode */
> +		page_flip_test(data, output, TEST_MODE_FLIP_ONLY, 20);
> +		ret = igt_amd_read_replay_coasting_vtotal(data->fd,
> +							  output->name,
> +							  &live_coasting_vtotal);
> +		igt_assert_f(ret == 0,
> +			     "failed to read live-mode coasting vtotal: %s\n",
> +			     strerror(-ret));
> +
> +		igt_fail_on_f(static_coasting_vtotal <= live_coasting_vtotal,
> +			      "coasting vtotal in static (%u) must be > live (%u)\n",
> +			      static_coasting_vtotal, live_coasting_vtotal);
> +
> +		igt_remove_fb(data->fd, &data->ref_fb);
> +		igt_remove_fb(data->fd, &data->ref_fb2);
> +		data->ref_fb.fb_id = 0;
> +		data->ref_fb2.fb_id = 0;
> +	}
> +
> +	test_fini(data);
> +}
> +
>   static int opt_handler(int option, int option_index, void *data)
>   {
>   	switch (option) {
> @@ -454,6 +537,9 @@ int igt_main_args("", long_options, help_str, opt_handler, NULL)
>   	igt_describe("Test whether Panel Replay can be enabled after resume from suspend");
>   	igt_subtest("replay_suspend") run_check_replay_suspend(&data);
>   
> +	igt_describe("Test whether Panel Replay can be enabled with rate control mode");
> +	igt_subtest("replay_rate_control") run_check_replay_rate_control(&data);
> +
>   	igt_fixture()
>   	{
>   		if (opt.visual_confirm) {


  reply	other threads:[~2026-05-12 15:42 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-12  7:59 [PATCH i-g-t 0/2] tests/amdgpu/amd_replay: Add Replay Rate Control test Ray Wu
2026-05-12  7:59 ` [PATCH i-g-t 1/2] tests/amdgpu/amd_replay: fix operator precedence and typos Ray Wu
2026-05-12 15:31   ` Alex Hung
2026-05-12  7:59 ` [PATCH i-g-t 2/2] tests/amdgpu/amd_replay: add Replay Rate Control IGT test Ray Wu
2026-05-12 15:40   ` Alex Hung [this message]
2026-05-12 13:31 ` ✓ i915.CI.BAT: success for tests/amdgpu/amd_replay: Add Replay Rate Control test Patchwork
2026-05-12 14:32 ` ✓ Xe.CI.BAT: " Patchwork
2026-05-13  1:24 ` ✗ Xe.CI.FULL: failure " Patchwork
2026-05-13  5:55 ` ✗ i915.CI.Full: " Patchwork

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ab6fa4a7-1c27-4d35-8df7-cbbed88f30e4@amd.com \
    --to=alex.hung@amd.com \
    --cc=chiahsuan.chung@amd.com \
    --cc=igt-dev@lists.freedesktop.org \
    --cc=ray.wu@amd.com \
    --cc=sunpeng.li@amd.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox