[PATCH i-g-t 1/1] tests/intel/kms_ccs: add hiberbate test
Rodrigo Vivi
rodrigo.vivi at intel.com
Tue Jan 28 22:53:33 UTC 2025
On Tue, Jan 28, 2025 at 01:55:58PM +0200, Juha-Pekka Heikkila wrote:
> Add hibernate test which bring entire system down for short
> hibernate. This mode is added to suspend tests to be run
> manually with '-r' flag because this is not ci friendly test,
hmm... why not '-f'?
-r won't get confused or accidentaly used since we have --r as an
alias for --run-subtest ?
But well, let's move ahead and add some option and you decide
the flag...
Reviewed-by: Rodrigo Vivi <rodrigo.vivi at intel.com>
> on hibernate ci would lose connection to the hibernated box.
>
> This test is written against Ubuntu distro relying grub
> configuration found there.
>
> For this test to work kernel resume point need to be set, from
> kernel command line is checked if there is found something along
> the lines of "resume=/dev/nvme0n1p2" or so to verify hibernate
> will be successful.
>
> Signed-off-by: Juha-Pekka Heikkila <juhapekka.heikkila at gmail.com>
> ---
> tests/intel/kms_ccs.c | 176 +++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 173 insertions(+), 3 deletions(-)
>
> diff --git a/tests/intel/kms_ccs.c b/tests/intel/kms_ccs.c
> index 3e9a57863..8be3c063a 100644
> --- a/tests/intel/kms_ccs.c
> +++ b/tests/intel/kms_ccs.c
> @@ -190,6 +190,7 @@ typedef struct {
> bool user_seed;
> enum igt_commit_style commit;
> int fb_list_length;
> + bool do_hibernate;
> struct {
> struct igt_fb fb;
> int width, height;
> @@ -271,6 +272,162 @@ static const struct {
> */
> #define MAX_SPRITE_PLANE_WIDTH 2000
>
> +
> +/**
> + * check_hibernation_support:
> + *
> + * Return: True if kernel is configured with resume point for hibernate.
> + */
> +static bool check_hibernation_support(void)
> +{
> + int fd;
> + char buffer[2048];
> + ssize_t bytes_read;
> + FILE *cmdline;
> +
> + /* Check if hibernation is supported in /sys/power/state */
> + fd = open("/sys/power/state", O_RDONLY);
> +
> + if (fd <= 0) {
> + igt_debug("Failed to open /sys/power/state\n");
> + return false;
> + }
> +
> + bytes_read = read(fd, buffer, sizeof(buffer) - 1);
> + close(fd);
> +
> + if (bytes_read <= 0) {
> + igt_debug("Failed to read /sys/power/state");
> + return false;
> + }
> +
> + buffer[bytes_read] = '\0';
> + if (strstr(buffer, "disk") == NULL) {
> + igt_debug("Hibernation (suspend to disk) is not supported on this system.\n");
> + return false;
> + }
> +
> + /* Check if resume is configured in kernel command line */
> + cmdline = fopen("/proc/cmdline", "r");
> +
> + if (!cmdline) {
> + igt_debug("Failed to open /proc/cmdline");
> + return false;
> + }
> +
> + fread(buffer, 1, sizeof(buffer) - 1, cmdline);
> + fclose(cmdline);
> +
> + if (strstr(buffer, "resume=") == NULL) {
> + igt_debug("Kernel does not have 'resume' parameter configured for hibernation.\n");
> + return false;
> + }
> +
> + return true;
> +}
> +
> +/**
> + * Ensure_grub_boots_same_kernel:
> + *
> + * Return: True if kernel was found and set for next reboot.
> + */
> +static bool ensure_grub_boots_same_kernel(void)
> +{
> + char cmdline[1024];
> + char current_kernel[256];
> + char last_menuentry[512] = "";
> + char grub_entry[512];
> + char command[1024];
> + FILE *cmdline_file, *grub_cfg;
> + char line[1024];
> + bool kernel_found = false;
> + char *kernel_arg;
> + char *kernel_end;
> +
> + /* Read /proc/cmdline to get the current kernel image */
> + cmdline_file = fopen("/proc/cmdline", "r");
> + if (!cmdline_file) {
> + igt_debug("Failed to open /proc/cmdline");
> + return false;
> + }
> +
> + if (!fgets(cmdline, sizeof(cmdline), cmdline_file)) {
> + fclose(cmdline_file);
> + igt_debug("Failed to read /proc/cmdline");
> + return false;
> + }
> + fclose(cmdline_file);
> +
> + /* Parse the kernel image from cmdline */
> + kernel_arg = strstr(cmdline, "BOOT_IMAGE=");
> + if (!kernel_arg) {
> + igt_debug("BOOT_IMAGE= not found in /proc/cmdline\n");
> + return false;
> + }
> +
> + kernel_arg += strlen("BOOT_IMAGE=");
> + kernel_end = strchr(kernel_arg, ' ');
> +
> + if (!kernel_end)
> + kernel_end = kernel_arg + strlen(kernel_arg);
> +
> + snprintf(current_kernel, sizeof(current_kernel), "%.*s",
> + (int)(kernel_end - kernel_arg), kernel_arg);
> + igt_debug("Current kernel image: %s\n", current_kernel);
> +
> + /* Open GRUB config file to find matching entry */
> + grub_cfg = fopen("/boot/grub/grub.cfg", "r");
> + if (!grub_cfg) {
> + igt_debug("Failed to open GRUB configuration file");
> + return false;
> + }
> +
> + while (fgets(line, sizeof(line), grub_cfg)) {
> + /* Check if the line contains a menuentry */
> + if (strstr(line, "menuentry")) {
> + /* Store the menuentry line */
> + char *start = strchr(line, '\'');
> + char *end = start ? strchr(start + 1, '\'') : NULL;
> +
> + if (start && end) {
> + snprintf(last_menuentry,
> + sizeof(last_menuentry),
> + "%.*s", (int)(end - start - 1),
> + start + 1);
> + }
> + }
> +
> + /* Check if the current line contains the kernel */
> + if (strstr(line, current_kernel)) {
> + /* Use the last seen menuentry as the match */
> + snprintf(grub_entry, sizeof(grub_entry), "%s",
> + last_menuentry);
> + kernel_found = true;
> + break;
> + }
> + }
> +
> + fclose(grub_cfg);
> +
> + if (!kernel_found) {
> + igt_debug("Failed to find matching GRUB entry for kernel: %s\n",
> + current_kernel);
> + return false;
> + }
> +
> + /* Set the GRUB boot target using grub-reboot */
> + snprintf(command, sizeof(command), "grub-reboot \"%s\"", grub_entry);
> + if (system(command) != 0) {
> + igt_debug("Failed to set GRUB boot target to: %s\n",
> + grub_entry);
> + return false;
> + }
> +
> + igt_debug("Set GRUB to boot kernel: %s (GRUB entry: %s)\n",
> + current_kernel, grub_entry);
> + return true;
> +}
> +
> static void addfb_init(struct igt_fb *fb, struct drm_mode_fb_cmd2 *f)
> {
> int i;
> @@ -839,8 +996,17 @@ static bool try_config(data_t *data, enum test_fb_flags fb_flags,
>
> if (ret == 0 && !(fb_flags & TEST_BAD_ROTATION_90) && crc) {
> if (data->flags & TEST_SUSPEND && fb_flags & FB_COMPRESSED) {
> - igt_system_suspend_autoresume(SUSPEND_STATE_MEM,
> - SUSPEND_TEST_NONE);
> + if (data->do_hibernate) {
> + igt_require_f(check_hibernation_support(),
> + "Kernel is not cofigured for resume\n");
> + igt_require_f(ensure_grub_boots_same_kernel(),
> + "Couldn't find correct kernel in grub.cfg\n");
> + igt_system_suspend_autoresume(SUSPEND_STATE_DISK,
> + SUSPEND_TEST_NONE);
> + } else {
> + igt_system_suspend_autoresume(SUSPEND_STATE_MEM,
> + SUSPEND_TEST_NONE);
> + }
>
> /* on resume check flat ccs is still compressed */
> if (is_xe_device(data->drm_fd) &&
> @@ -1044,6 +1210,9 @@ static int opt_handler(int opt, int opt_index, void *opt_data)
> data->user_seed = true;
> data->seed = strtoul(optarg, NULL, 0);
> break;
> + case 'r':
> + data->do_hibernate = true;
> + break;
> default:
> return IGT_OPT_HANDLER_ERROR;
> }
> @@ -1056,9 +1225,10 @@ static data_t data;
> static const char *help_str =
> " -c\t\tCheck the presence of compression meta-data\n"
> " -s <seed>\tSeed for random number generator\n"
> +" -r\t\tOn suspend test do full hibernate with reboot\n"
> ;
>
> -igt_main_args("cs:", NULL, help_str, opt_handler, &data)
> +igt_main_args("csr:", NULL, help_str, opt_handler, &data)
> {
> igt_fixture {
> data.drm_fd = drm_open_driver_master(DRIVER_INTEL | DRIVER_XE);
> --
> 2.45.2
>
More information about the igt-dev
mailing list