From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 1C700CD6E68 for ; Thu, 4 Jun 2026 07:38:19 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id C0029113D3D; Thu, 4 Jun 2026 07:38:18 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (2048-bit key; unprotected) header.d=intel.com header.i=@intel.com header.b="b/qwyq4q"; dkim-atps=neutral Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.15]) by gabe.freedesktop.org (Postfix) with ESMTPS id E8C03113D3D for ; Thu, 4 Jun 2026 07:37:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1780558677; x=1812094677; h=from:to:cc:subject:date:message-id:mime-version: content-transfer-encoding; bh=Ttrk2BC8eaQpCIvNOPQreL/Ur9BbRGNRrb6sk82Xj7Y=; b=b/qwyq4qLG+lCZEswqbGFiXheXfuN80wYQuO2taYW4Kv/JLaOxk0NU2d 829ZfKV8rc9TdMt6sNWgB5py53sPS0PY4u2rr4ZW2BDmID6WT9AGsX4tu EMOKIYro/joT9CMHBfIQw/pluJdnqrPkLnW0yNHUgh3HYxLzeotXKt6LU mrugZprFjCSjzopxYB1ibfJqVJa+AEsWqm7XifDTvsH62z+cAUEZXM4Pl w7gpJ2//QAq8Ixtm4YWbQNRez5GcYYpFwHCVNh/sZa3cqM3mayQ/CqXmJ gUMnY8kMWXBF2wP56joDJhNMSu50+GxfUsO/Gencuej6a1xxBAcMCWAdS A==; X-CSE-ConnectionGUID: ztSAmf/FTim2yWkiRN/70w== X-CSE-MsgGUID: MXkM4IX+SxCCzE3CQWHj1Q== X-IronPort-AV: E=McAfee;i="6800,10657,11806"; a="81505974" X-IronPort-AV: E=Sophos;i="6.24,186,1774335600"; d="scan'208";a="81505974" Received: from fmviesa009.fm.intel.com ([10.60.135.149]) by fmvoesa109.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Jun 2026 00:37:46 -0700 X-CSE-ConnectionGUID: +mMoCu5tQc+6SE6lLIoBbg== X-CSE-MsgGUID: 5JINzkwuQS25EnFOMjpLlQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.24,186,1774335600"; d="scan'208";a="238133031" Received: from dut6245dg2frd.fm.intel.com ([10.36.24.131]) by fmviesa009-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Jun 2026 00:37:46 -0700 From: Sobin Thomas To: igt-dev@lists.freedesktop.org, piotr.piorkowski@intel.com Cc: Sobin Thomas Subject: [PATCH i-g-t v1] tests/xe_debugfs: Add debugfs entry read/write validation in root-dir Date: Thu, 4 Jun 2026 07:37:40 +0000 Message-ID: <20260604073740.332572-1-sobin.thomas@intel.com> X-Mailer: git-send-email 2.52.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: igt-dev@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development mailing list for IGT GPU Tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: igt-dev-bounces@lists.freedesktop.org Sender: "igt-dev" Extend the root-dir subtest to validate additional Xe debugfs entries: - dgfx_pkg_residencies: Validate counter reads (optional, non-empty) - dgfx_pcie_link_residencies: Validate PCIE LINK string content (optional) - sriov_info: Validate entry is non-empty (optional) - workarounds: Validate entry is non-empty (optional) - atomic_svm_timeslice_ms: Validate integer read/write (optional) - poor_man_system_atomic_support: Validate boolean read/write (optional) - disable_late_binding: Validate boolean read/write (optional) Signed-off-by: Sobin Thomas --- tests/intel/xe_debugfs.c | 192 +++++++++++++++++++++++++++++++++++---- 1 file changed, 174 insertions(+), 18 deletions(-) diff --git a/tests/intel/xe_debugfs.c b/tests/intel/xe_debugfs.c index 587e3e785..1c4a47ac6 100644 --- a/tests/intel/xe_debugfs.c +++ b/tests/intel/xe_debugfs.c @@ -39,11 +39,24 @@ IGT_TEST_DESCRIPTION("Validate Xe debugfs devnodes and their contents"); __m && ((__i) = __builtin_ctz(__m), 1); \ __m &= __m - 1) +/* Validation types for debugfs read tests */ +enum debugfs_validate_type { + VALIDATE_NONE, /* Just check file exists */ + VALIDATE_NON_EMPTY, /* Just check buffer is not empty */ + VALIDATE_CONTAINS_STR, /* Check buffer contains expected string */ + VALIDATE_INT_GE_ZERO, /* Parse as integer, verify >= 0 */ + VALIDATE_BOOL, /* Check bool value (0 or 1) */ +}; + struct check_entry { const char *name_fmt; int mode; - bool (*condition)(struct xe_device *xe_dev); + bool optional; + bool (*condition)(struct xe_device *xe_dev, void *params); + void *cond_params; unsigned int (*iter_mask)(struct xe_device *xe_dev); + enum debugfs_validate_type validate; + const char *expected_str; }; static unsigned int gt_iter_mask(struct xe_device *xe_dev) @@ -56,7 +69,7 @@ static unsigned int tile_iter_mask(struct xe_device *xe_dev) return xe_dev->tile_mask; } -static bool has_vram(struct xe_device *xe_dev) +static bool has_vram_region(struct xe_device *xe_dev, void *params) { return xe_dev->has_vram; } @@ -131,16 +144,140 @@ static bool find_not_tested_files(int dir_fd, struct igt_list_head *hit_entries) return found_not_tested; } -static bool file_in_dir_exists(int dirfd, const char *file_name, int mode) +/* Validate that debugfs buffer is non-empty or contains expected string */ +static bool validate_string(int dirfd, const char *file_name, const char *expected_str) +{ + char buf[4096]; + int ret = 0; + + ret = igt_sysfs_read(dirfd, file_name, buf, sizeof(buf) - 1); + if (ret < 0) + return false; + buf[ret] = '\0'; + + /* Check for empty buffer */ + if (strlen(buf) == 0) { + igt_warn("Empty output from %s\n", file_name); + return false; + } + + /* If expecting specific string, verify it's present */ + if (expected_str && !strstr(buf, expected_str)) { + igt_warn("Expected '%s' not found in %s\n", expected_str, file_name); + return false; + } + + if (expected_str) + igt_debug("Successfully read %s: found '%s'\n", file_name, expected_str); + else + igt_debug("Successfully read %s: %zd bytes\n%s\n", file_name, strlen(buf), buf); + + return true; +} + +static const char *mode_to_str(int mode) +{ + switch (mode & O_ACCMODE) { + case O_RDONLY: return "RO"; + case O_WRONLY: return "WO"; + case O_RDWR: return "RW"; + default: return "UNKNOWN"; + } +} + +static bool validate_bool_file(int dirfd, const char *file_name, int mode) +{ + int orig_val = 0, read_val = 0, test_val = 0; + + if (igt_sysfs_scanf(dirfd, file_name, "%d", &orig_val) != 1 || + (orig_val != 0 && orig_val != 1)) + return false; + + if (mode == O_RDWR) { + test_val = (orig_val == 0) ? 1 : 0; + + if (igt_sysfs_printf(dirfd, file_name, "%d", test_val) < 0) + return false; + + if (igt_sysfs_scanf(dirfd, file_name, "%d", &read_val) != 1 || read_val != test_val) + return false; + + /* Restore original value */ + if (igt_sysfs_printf(dirfd, file_name, "%d", orig_val) < 0) { + igt_warn("Failed to restore original value for %s\n", file_name); + return false; + } + } + + igt_info("Successfully validated %s bool %s\n", mode_to_str(mode), file_name); + return true; +} + +static bool validate_int_file(int dirfd, const char *file_name, int mode) { - int fd = openat(dirfd, file_name, mode); + long orig_val = 0, new_val = 0, read_val = 0; + + if (igt_sysfs_scanf(dirfd, file_name, "%ld", &orig_val) != 1) + return false; + + if (orig_val < 0) + return false; + + if (mode == O_RDWR) { + new_val = orig_val + 1; + if (igt_sysfs_printf(dirfd, file_name, "%ld", new_val) < 0) + return false; + if (igt_sysfs_scanf(dirfd, file_name, "%ld", &read_val) != 1) + return false; + if (read_val != new_val) + return false; + /* Restore original value */ + if (igt_sysfs_printf(dirfd, file_name, "%ld", orig_val) < 0) { + igt_warn("Failed to restore original value for %s\n", file_name); + return false; + } - if (fd >= 0) { - close(fd); + igt_debug("Successfully validated %s int %s: %ld -> %ld -> %ld\n", + mode_to_str(mode), file_name, orig_val, new_val, orig_val); + } else { + igt_debug("Successfully validated %s int %s: %ld\n", + mode_to_str(mode), file_name, orig_val); + } + return true; +} + +static bool validate_debugfs_file(int dirfd, const char *file_name, int mode, + enum debugfs_validate_type validate, const char *expected_str) +{ + bool result = true; + + if (faccessat(dirfd, file_name, F_OK, 0) < 0) { + igt_debug("%s does not exist\n", file_name); + return false; + } + if (validate == VALIDATE_NONE) return true; + + switch (validate) { + case VALIDATE_NON_EMPTY: + result = validate_string(dirfd, file_name, NULL); + break; + case VALIDATE_CONTAINS_STR: + result = validate_string(dirfd, file_name, expected_str); + break; + case VALIDATE_INT_GE_ZERO: + result = validate_int_file(dirfd, file_name, mode); + break; + case VALIDATE_BOOL: + result = validate_bool_file(dirfd, file_name, mode); + break; + default: + igt_warn("Unknown validate type %d for %s\n", validate, file_name); + result = false; + break; } - return false; + return result; } /* @@ -160,7 +297,7 @@ static int debugfs_validate_entries(struct xe_device *xe_dev, int dir_fd, unsigned int mask; unsigned int j; - if (check->condition && !check->condition(xe_dev)) + if (check->condition && !check->condition(xe_dev, check->cond_params)) continue; if (!check->iter_mask) @@ -209,10 +346,18 @@ static int debugfs_validate_entries(struct xe_device *xe_dev, int dir_fd, #pragma GCC diagnostic pop } - if (!file_in_dir_exists(dir_fd, entry->name, check->mode)) { - igt_warn("Missing debugfs file: %s\n", entry->name); - missing_count++; + if (!validate_debugfs_file(dir_fd, entry->name, check->mode, + check->validate, check->expected_str)) { + if (check->optional) { + igt_info("Optional entry %s not found/invalid (skipped)\n", + entry->name); + } else { + igt_warn("Missing or invalid debugfs file: %s\n", + entry->name); + missing_count++; + } } + } } @@ -239,14 +384,25 @@ out: static void test_root_dir(struct xe_device *xe_dev) { const struct check_entry expected_files[] = { - { "clients", O_RDONLY }, + { "clients", O_RDONLY, .validate = VALIDATE_NON_EMPTY }, + { "disable_late_binding", O_RDWR, .optional = true, .validate = VALIDATE_BOOL }, { "forcewake_all", O_WRONLY }, { "gem_names", O_RDONLY }, - { "gt%u", O_RDONLY, NULL, gt_iter_mask }, /* gt0, gt1, ... */ - { "gtt_mm", O_RDONLY }, - { "info", O_RDONLY }, - { "name", O_RDONLY }, - { "tile%u", O_RDONLY, NULL, tile_iter_mask }, /* tile0, tile1, ... */ + { "gt%u", O_RDONLY, .iter_mask = gt_iter_mask }, + { "gtt_mm", O_RDONLY, }, + { "info", O_RDONLY, .validate = VALIDATE_NON_EMPTY }, + { "name", O_RDONLY, .validate = VALIDATE_NON_EMPTY }, + { "poor_man_system_atomic_support", O_RDWR, .optional = true, + .validate = VALIDATE_BOOL }, + { "dgfx_pkg_residencies", O_RDONLY, .optional = true, + .validate = VALIDATE_NON_EMPTY }, + { "dgfx_pcie_link_residencies", O_RDONLY, .optional = true, + .validate = VALIDATE_CONTAINS_STR, .expected_str = "PCIE LINK" }, + { "sriov_info", O_RDONLY, .optional = true, .validate = VALIDATE_NON_EMPTY }, + { "workarounds", O_RDONLY, .optional = true, .validate = VALIDATE_NON_EMPTY }, + { "atomic_svm_timeslice_ms", O_RDWR, .optional = true, + .validate = VALIDATE_INT_GE_ZERO }, + { "tile%u", O_RDONLY, .iter_mask = tile_iter_mask }, }; int debugfs_fd = igt_debugfs_dir(xe_dev->fd); int missing_count; @@ -276,7 +432,7 @@ static void test_tile_dir(struct xe_device *xe_dev, uint8_t tile) const struct check_entry expected_files[] = { { "ggtt", O_RDONLY }, { "sa_info", O_RDONLY }, - { "vram_mm", O_RDONLY, has_vram }, + { "vram_mm", O_RDONLY, .condition = has_vram_region, .cond_params = (void *)&tile }, }; int debugfs_fd = igt_debugfs_tile_dir(xe_dev->fd, tile); int missing_count; -- 2.52.0