All of 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.