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) {
next prev parent 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