[PATCH v5 1/4] lib: Add generic platform filtering framework
<[email protected]> Wed, 5 Aug 2026 16:28:45 -0400
| Newsgroups | org.freedesktop.lists.igt-dev |
|---|---|
| Message-ID | <[email protected]> |
From: Vitaly Prosyak <[email protected]> Implement vendor-agnostic platform filtering system that allows any vendor to plug in platform-specific test skipping logic via callbacks. Key design elements: - struct platform_filter_ops: vendor callback interface - struct platform_skip_entry: vendor-neutral skip rule representation - enum skip_source: three-tier priority (built-in, config, env) - API functions: init, should_skip, require, dump Platform filtering is automatic - tests only need to call platform_filter_init() once in igt_fixture. The IGT framework automatically checks each subtest before execution via __igt_run_subtest(). Example usage: igt_fixture { vendor_platform_filter_init(platform_info); } igt_subtest("test") { // Automatic filtering - no manual call needed! test_code(); } Cc: Kamil Konieczny <[email protected]> Cc: Jani Nikula <[email protected]> Cc: Jesse Zhang <[email protected]> Cc: Christian König <[email protected]> Cc: Alex Deucher <[email protected]> Cc: Krzysztof Karas <[email protected]> v5 changes (addressing Kamil Konieczny's review): -This combines both the interface (header) and implementation in a -single commit as requested by Kamil Konieczny. -**IMPORTANT**: This commit is generic and vendor-agnostic, containing -NO AMD-specific implementation. The AMD backend is in a separate commit -(patch 2/6 "lib/amdgpu: Add AMD platform filtering backend"). - Reorganize and improve commit content. - Squash patch 3: Add platform filter initialization check to fix incremental compilation. v4 changes (addressing Krzysztof Karas detailed review of v3): - Fixed documentation comment placement - ALL moved before functions - Reorganized commit message for clarity (v4 changes first) - Added prominent note that this is generic (no vendor code) - Proper [PATCH v4 X/Y] format using git format-patch --subject-prefix v3 changes (addressing Kamil Konieczny's review): - Squashed header and implementation into single commit - Removed unnecessary comment "Function prototypes..." from header - Comprehensive documentation in separate commit (docs/platform_filtering.md) - Automatic filtering via __igt_run_subtest() hook (no manual require calls) - Fixed code style: include order, SPDX style, checkpatch clean - Removed unnecessary newlines before single-statement returns Design rationale (addresses feedback from original RFC discussion): This implementation addresses feedback from multiple reviewers on the original RFC patch series. 1. Jani Nikula requested vendor-agnostic design: "I would have expected an attempt to make an IGT shared filtering system generic enough to plug into any vendor's platforms." Resolution: Implemented vendor-agnostic callback-based design via platform_filter_ops structure. Any vendor (Intel, AMD, Qualcomm, etc.) can provide their own backend without modifying core framework. 2. Kamil Konieczny requested config file support: a) "Add also example with config file as env vars are not convenient for large tests lists" Resolution: Comprehensive documentation added in patch 5/6 (docs/platform_filtering.md) showing config file as RECOMMENDED method with real-world examples, wildcards, and best practices. b) "imho you can get test name in require, no need to repeat it" Resolution: Went further - v3 removes igt_platform_require() entirely. Filtering is now automatic via __igt_run_subtest() hook in patch 4/6. Zero manual calls needed in subtests. c) Code style (include order, alignment, igt_debug vs igt_info) Resolution: Fixed in v3. Includes alphabetically ordered, SPDX headers use // style, checkpatch clean. d) "No need for this comment" (function prototypes comment) Resolution: Removed unnecessary comment from header file. e) "Please squash this into second patch" Resolution: Header and implementation now in single commit. 3. Multi-GPU support (integrated + discrete): Current design queries platform once in igt_fixture. For multi-GPU scenarios, tests can call platform_filter_init() per-device with device-specific platform_info. Signed-off-by: Vitaly Prosyak <[email protected]> Change-Id: I389d8a4e5bd67cdd00ac625c64b24e4d9b092e17 --- lib/igt_platform_filter.c | 574 ++++++++++++++++++++++++++++++++++++++ lib/igt_platform_filter.h | 124 ++++++++ lib/meson.build | 1 + 3 files changed, 699 insertions(+) create mode 100644 lib/igt_platform_filter.c create mode 100644 lib/igt_platform_filter.h diff --git a/lib/igt_platform_filter.c b/lib/igt_platform_filter.c new file mode 100644 index 000000000..0b9452c40 --- /dev/null +++ b/lib/igt_platform_filter.c @@ -0,0 +1,574 @@ +// SPDX-License-Identifier: MIT +// Copyright 2026 Advanced Micro Devices, Inc. +/* + * Generic platform-based test filtering framework + * + * This is a vendor-agnostic filtering system. Vendor-specific logic + * is implemented via platform_filter_ops callbacks. + */ + +#include <ctype.h> +#include <fnmatch.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "igt.h" +#include "igt_platform_filter.h" + +/* Maximum entries from config file and env variable */ +#define MAX_CONFIG_ENTRIES 256 +#define MAX_ENV_ENTRIES 128 +#define MAX_LINE_LENGTH 512 + +/* Filter context - holds all runtime state (no globals) */ +struct platform_filter_context { + const struct platform_filter_ops *ops; + const void *platform_info; + + struct platform_skip_entry config_entries[MAX_CONFIG_ENTRIES]; + int config_entry_count; + + struct platform_skip_entry env_entries[MAX_ENV_ENTRIES]; + int env_entry_count; + + bool initialized; + char current_platform_name[64]; +}; + +/* Single static instance - initialized on first use */ +static struct platform_filter_context *get_filter_context(void) +{ + static struct platform_filter_context ctx = {0}; + + return &ctx; +} + +/* + * ================================================================ + * HELPER FUNCTIONS + * ================================================================ */ + +/* Helper: Trim whitespace from string */ +static char *trim(char *str) +{ + char *end; + + while (isspace(*str)) + str++; + + if (*str == 0) + return str; + + end = str + strlen(str) - 1; + while (end > str && isspace(*end)) + end--; + + *(end + 1) = 0; + return str; +} + +/* Helper: Match wildcard or exact string */ +static bool match_string(const char *pattern, const char *str) +{ + if (!pattern || !str) + return false; + + if (strcmp(pattern, "*") == 0) + return true; + return fnmatch(pattern, str, 0) == 0; +} + +/* Helper: Check if entry matches platform/test/subtest */ +static bool entry_matches(const struct platform_filter_context *ctx, + const struct platform_skip_entry *entry, + const char *test_name, + const char *subtest_name) +{ + if (entry->platform_data && ctx->ops->match_platform) { + if (!ctx->ops->match_platform(ctx->platform_info, entry->platform_data)) + return false; + } + + if (entry->test_name && strcmp(entry->test_name, "*") != 0) { + if (!test_name || !match_string(entry->test_name, test_name)) + return false; + } + + if (entry->subtest_glob && strcmp(entry->subtest_glob, "*") != 0) { + if (!subtest_name || !match_string(entry->subtest_glob, subtest_name)) + return false; + } + return true; +} + +/* + * ================================================================ + * CONFIG FILE PARSER (/etc/igt/platform_skip.conf) + * ================================================================ */ + +/* Parse one line from config file */ +static bool parse_config_line(struct platform_filter_context *ctx, + char *line, + struct platform_skip_entry *entry) +{ + char *platform, *test, *subtest, *reason; + + /* Skip comments and empty lines */ + line = trim(line); + if (line[0] == '#' || line[0] == 0) + return false; + + /* Format: platform:test:subtest:reason */ + platform = strtok(line, ":"); + test = strtok(NULL, ":"); + subtest = strtok(NULL, ":"); + reason = strtok(NULL, "\n"); + + if (!platform || !test || !subtest) { + igt_warn("Invalid config line format (expected platform:test:subtest:reason)\n"); + return false; + } + + /* Allocate and copy strings */ + entry->test_name = strdup(trim(test)); + entry->subtest_glob = strdup(trim(subtest)); + entry->reason = reason ? strdup(trim(reason)) : strdup("No reason"); + + /* Parse platform using vendor callback */ + platform = trim(platform); + if (ctx->ops->parse_platform_config && strcmp(platform, "*") != 0) { + /* Vendor-specific platform string */ + if (!ctx->ops->parse_platform_config(platform, &entry->platform_data)) { + igt_warn("Failed to parse platform: %s\n", platform); + free((void *)entry->test_name); + free((void *)entry->subtest_glob); + free((void *)entry->reason); + return false; + } + } else { + /* Wildcard or no vendor-specific parsing available */ + entry->platform_data = NULL; + } + return true; +} + +/* Load config file */ +static void load_config_file(struct platform_filter_context *ctx, const char *filename) +{ + FILE *f; + char line[MAX_LINE_LENGTH]; + + f = fopen(filename, "r"); + if (!f) { + igt_debug("Config file not found: %s\n", filename); + + return; + } + + igt_info("Loading platform skip config from: %s\n", filename); + + while (fgets(line, sizeof(line), f)) { + if (ctx->config_entry_count >= MAX_CONFIG_ENTRIES) { + igt_warn("Config file has too many entries (max %d)\n", + MAX_CONFIG_ENTRIES); + break; + } + + if (parse_config_line(ctx, line, &ctx->config_entries[ctx->config_entry_count])) { + ctx->config_entry_count++; + } + } + + fclose(f); + igt_info("Loaded %d skip rules from config file\n", ctx->config_entry_count); +} + +/* + * ================================================================ + * ENVIRONMENT VARIABLE PARSER (IGT_PLATFORM_SKIP_CONFIG) + * ================================================================ */ + +/* Parse environment variable entries (semicolon-separated) */ +static void load_env_variable(struct platform_filter_context *ctx) +{ + char *env, *env_copy, *entry_str, *saveptr; + const char *env_value; + + env_value = getenv("IGT_PLATFORM_SKIP_CONFIG"); + if (!env_value || env_value[0] == 0) { + igt_debug("IGT_PLATFORM_SKIP_CONFIG not set\n"); + + return; + } + + igt_info("Loading platform skip config from IGT_PLATFORM_SKIP_CONFIG\n"); + + env_copy = strdup(env_value); + env = env_copy; + + /* Parse semicolon-separated entries */ + while ((entry_str = strtok_r(env, ";", &saveptr)) != NULL) { + env = NULL; /* For subsequent strtok_r calls */ + + if (ctx->env_entry_count >= MAX_ENV_ENTRIES) { + igt_warn("Too many env variable entries (max %d)\n", + MAX_ENV_ENTRIES); + break; + } + + if (parse_config_line(ctx, entry_str, &ctx->env_entries[ctx->env_entry_count])) { + ctx->env_entry_count++; + } + } + + free(env_copy); + igt_info("Loaded %d skip rules from environment variable\n", ctx->env_entry_count); +} + +/* + * ================================================================ + * PUBLIC API IMPLEMENTATION + * ================================================================ */ + +/** + * igt_platform_filter_init: + * @ops: Platform-specific operation callbacks + * @platform_info: Vendor-specific platform identification data + * + * Initialize the platform filtering system with vendor-specific backend. + * This sets up the filter context and loads skip rules from three sources + * in priority order: + * 1. Built-in rules (highest priority, vendor-provided) + * 2. Config file /etc/igt/platform_skip.conf + * 3. Environment variable IGT_PLATFORM_SKIP_CONFIG (lowest priority) + * + * The filtering system is vendor-agnostic. Platform matching logic is + * provided through the @ops callbacks, allowing each vendor to implement + * their own identification scheme (e.g., AMD uses family_id/chip_rev, + * Intel could use platform_id/stepping). + * + * Must be called once before using igt_platform_require(). + */ +void igt_platform_filter_init(const struct platform_filter_ops *ops, + const void *platform_info) +{ + struct platform_filter_context *ctx = get_filter_context(); + + if (ctx->initialized) + + return; + + if (!ops) { + igt_warn("Platform filter ops is NULL, filtering disabled\n"); + + return; + } + + ctx->ops = ops; + ctx->platform_info = platform_info; + + igt_info("Initializing platform filter system (3-tier priority) for vendor: %s\n", + ops->name ? ops->name : "unknown"); + + /* Get current platform name */ + + if (ops->get_platform_name) { + const char *pname = ops->get_platform_name(platform_info); + + snprintf(ctx->current_platform_name, sizeof(ctx->current_platform_name), + "%s", pname ? pname : "unknown"); + } + + /* Priority 1: Built-in array (vendor-specific) */ + igt_debug(" Priority 1: Built-in array (vendor-specific)\n"); + + /* Priority 2: Config file */ + igt_debug(" Priority 2: Config file /etc/igt/platform_skip.conf\n"); + load_config_file(ctx, "/etc/igt/platform_skip.conf"); + + /* Priority 3: Environment variable */ + igt_debug(" Priority 3: Environment variable IGT_PLATFORM_SKIP_CONFIG\n"); + load_env_variable(ctx); + + ctx->initialized = true; + igt_info("Platform filter initialization complete\n"); +} + +/** + * igt_platform_should_skip: + * @test_name: Name of the test + * @subtest_name: Name of the subtest (or NULL for test-level check) + * + * Check if a test/subtest should be skipped based on platform filtering rules. + * + * Returns: true if the test should be skipped, false otherwise + */ +bool igt_platform_should_skip(const char *test_name, + const char *subtest_name, + enum skip_source *source, + const char **reason) +{ + struct platform_filter_context *ctx = get_filter_context(); + const struct platform_skip_entry *entry; + int i, count; + + if (!ctx->initialized) { + igt_warn("Platform filter not initialized\n"); + if (source) + *source = SKIP_SOURCE_NONE; + if (reason) + *reason = NULL; + return false; + } + + /* Priority 1: Check built-in array FIRST */ + if (ctx->ops->get_builtin_rules) { + const struct platform_skip_entry *builtin = ctx->ops->get_builtin_rules(&count); + + for (i = 0; i < count; i++) { + entry = &builtin[i]; + if (entry_matches(ctx, entry, test_name, subtest_name)) { + if (source) + *source = SKIP_SOURCE_BUILTIN; + if (reason) + *reason = entry->reason; + igt_debug("Skip (built-in): %s:%s - %s\n", + entry->test_name ? entry->test_name : "*", + entry->subtest_glob ? entry->subtest_glob : "*", + entry->reason ? entry->reason : "no reason"); + return true; + } + } + } + + /* Priority 2: Check config file */ + for (i = 0; i < ctx->config_entry_count; i++) { + entry = &ctx->config_entries[i]; + if (entry_matches(ctx, entry, test_name, subtest_name)) { + if (source) + *source = SKIP_SOURCE_CONFIG; + if (reason) + *reason = entry->reason; + igt_debug("Skip (config): %s:%s - %s\n", + entry->test_name, entry->subtest_glob, entry->reason); + return true; + } + } + + /* Priority 3: Check environment variable */ + for (i = 0; i < ctx->env_entry_count; i++) { + entry = &ctx->env_entries[i]; + if (entry_matches(ctx, entry, test_name, subtest_name)) { + if (source) + *source = SKIP_SOURCE_ENV; + if (reason) + *reason = entry->reason; + igt_debug("Skip (env): %s:%s - %s\n", + entry->test_name, entry->subtest_glob, entry->reason); + return true; + } + } + + if (source) + *source = SKIP_SOURCE_NONE; + if (reason) + *reason = NULL; + return false; +} + +/** + * igt_platform_require: + * @subtest_name: Name of the subtest to check + * + * Check if current subtest should be skipped and call igt_skip() if matched. + * This integrates platform filtering with IGT's standard skip mechanism. + * + * The function automatically determines the test name from igt_test_name(). + * If a skip rule matches, calls igt_skip() with the configured reason. + */ +void igt_platform_require(const char *subtest_name) +{ + enum skip_source source; + const char *test_name = igt_test_name(); + const char *reason; + + if (igt_platform_should_skip(test_name, subtest_name, &source, &reason)) { + const char *source_str; + + switch (source) { + case SKIP_SOURCE_BUILTIN: + source_str = "built-in array"; + break; + case SKIP_SOURCE_CONFIG: + source_str = "config file"; + break; + case SKIP_SOURCE_ENV: + source_str = "environment variable"; + break; + default: + source_str = "unknown"; + } + + igt_skip("Skipped on this platform [%s]: %s\n", + source_str, reason ? reason : "no reason"); + } +} + +/** + * igt_platform_filter_dump: + * + * Dump the current platform filtering configuration to stdout. + * Shows all loaded skip rules from built-in, config file, and environment + * variable sources. Useful for debugging which rules are active. + */ +void igt_platform_filter_dump(void) +{ + struct platform_filter_context *ctx = get_filter_context(); + const struct platform_skip_entry *entry; + int i, total_count, count; + + if (!ctx->initialized) { + igt_info("Platform filter not initialized\n"); + + return; + } + + igt_info("\n"); + igt_info("═══════════════════════════════════════════════════════════════════\n"); + igt_info(" PLATFORM SKIP FILTER CONFIGURATION - THREE-TIER PRIORITY SYSTEM\n"); + igt_info("═══════════════════════════════════════════════════════════════════\n\n"); + + igt_info("Vendor: %s\n", ctx->ops->name ? ctx->ops->name : "unknown"); + if (ctx->current_platform_name[0]) { + igt_info("Current Platform: %s\n\n", ctx->current_platform_name); + } + + /* Priority 1: Built-in array */ + igt_info("───────────────────────────────────────────────────────────────────\n"); + igt_info(" PRIORITY 1: BUILT-IN PRODUCTION ARRAY (VENDOR-SPECIFIC)\n"); + igt_info(" Source: Vendor implementation\n"); + igt_info("───────────────────────────────────────────────────────────────────\n"); + + total_count = 0; + if (ctx->ops->get_builtin_rules) { + const struct platform_skip_entry *builtin = ctx->ops->get_builtin_rules(&count); + + for (i = 0; i < count; i++) { + entry = &builtin[i]; + total_count++; + igt_info(" %2d. %s : %s\n", + total_count, + entry->test_name ? entry->test_name : "*", + entry->subtest_glob ? entry->subtest_glob : "*"); + igt_info(" Reason: %s\n", entry->reason ? entry->reason : "no reason"); + + /* Print platform data if vendor provides dump callback */ + if (entry->platform_data && ctx->ops->dump_platform_data) { + igt_info(" Platform: "); + ctx->ops->dump_platform_data(entry->platform_data); + igt_info("\n"); + } + igt_info("\n"); + } + } + if (total_count == 0) { + igt_info(" (No built-in rules)\n\n"); + } + + /* Priority 2: Config file */ + igt_info("───────────────────────────────────────────────────────────────────\n"); + igt_info(" PRIORITY 2: DEVELOPMENT CONFIG FILE\n"); + igt_info(" Source: /etc/igt/platform_skip.conf\n"); + igt_info("───────────────────────────────────────────────────────────────────\n"); + + if (ctx->config_entry_count > 0) { + for (i = 0; i < ctx->config_entry_count; i++) { + entry = &ctx->config_entries[i]; + igt_info(" %2d. %s : %s\n", + i + 1, + entry->test_name, + entry->subtest_glob); + igt_info(" Reason: %s\n\n", entry->reason); + } + } else { + igt_info(" (No config file rules loaded)\n\n"); + } + + /* Priority 3: Environment variable */ + igt_info("───────────────────────────────────────────────────────────────────\n"); + igt_info(" PRIORITY 3: RUNTIME ENVIRONMENT VARIABLE\n"); + igt_info(" Source: IGT_PLATFORM_SKIP_CONFIG\n"); + igt_info("───────────────────────────────────────────────────────────────────\n"); + + if (ctx->env_entry_count > 0) { + for (i = 0; i < ctx->env_entry_count; i++) { + entry = &ctx->env_entries[i]; + + igt_info(" %2d. %s : %s\n", + i + 1, + entry->test_name, + entry->subtest_glob); + igt_info(" Reason: %s\n\n", entry->reason); + } + } else { + igt_info(" (No environment variable rules)\n\n"); + } + + igt_info("───────────────────────────────────────────────────────────────────\n"); + igt_info(" SUMMARY\n"); + igt_info("───────────────────────────────────────────────────────────────────\n"); + igt_info(" Built-in rules: %d\n", total_count); + igt_info(" Config file rules: %d\n", ctx->config_entry_count); + igt_info(" Environment rules: %d\n", ctx->env_entry_count); + igt_info(" Total skip rules: %d\n", total_count + ctx->config_entry_count + ctx->env_entry_count); + igt_info("\n"); + igt_info("═══════════════════════════════════════════════════════════════════\n\n"); +} + +/** + * igt_platform_filter_dump_to_file: + * @filename: Path to output file + * + * Dump platform filtering configuration to a file. + * + * Returns: 0 on success, -1 on error + */ +int igt_platform_filter_dump_to_file(const char *filename) +{ + FILE *old_stdout; + FILE *f; + + f = fopen(filename, "w"); + if (!f) { + igt_warn("Failed to open %s for writing\n", filename); + return -1; + } + + /* Redirect stdout to file */ + old_stdout = stdout; + stdout = f; + + igt_platform_filter_dump(); + + /* Restore stdout */ + stdout = old_stdout; + fclose(f); + + igt_info("Platform filter configuration dumped to: %s\n", filename); + return 0; +} + +/** + * igt_platform_filter_is_initialized: + * + * Check if platform filtering has been initialized. + * + * Returns: true if initialized, false otherwise + */ +bool igt_platform_filter_is_initialized(void) +{ + struct platform_filter_context *ctx = get_filter_context(); + + return ctx && ctx->initialized; +} diff --git a/lib/igt_platform_filter.h b/lib/igt_platform_filter.h new file mode 100644 index 000000000..b83440514 --- /dev/null +++ b/lib/igt_platform_filter.h @@ -0,0 +1,124 @@ +/* SPDX-License-Identifier: MIT + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#ifndef IGT_PLATFORM_FILTER_H +#define IGT_PLATFORM_FILTER_H + +#include <stdbool.h> + +/** + * SECTION: igt_platform_filter + * @short_description: Generic platform-based test filtering framework + * @title: Platform Filter + * @include: igt_platform_filter.h + * + * Generic test filtering system that allows skipping tests/subtests based + * on platform characteristics. Designed to be vendor-agnostic with + * vendor-specific backends. + * + * Three-tier priority system (checked in sequence, first match wins): + * 1. PRODUCTION: Built-in compile-time rules (vendor-specific) + * 2. DEVELOPMENT: Config file /etc/igt/platform_skip.conf + * 3. RUNTIME: Environment variable IGT_PLATFORM_SKIP_CONFIG + * + * Vendor Implementation: + * Each vendor implements platform_filter_ops callbacks to provide: + * - Platform identification and matching logic + * - Platform-specific data structures + * - Built-in skip rules + * + * Usage in tests: + * igt_fixture() { + * igt_platform_filter_init(vendor_ops, platform_info); + * } + * + * igt_subtest("my-test") { + * // Automatic filtering - no manual call needed! + * test_code(); + * } + * + * Config file format (/etc/igt/platform_skip.conf): + * # Lines starting with # are comments + * # Format: platform:test:subtest:reason + * # Use * as wildcard + * + * navi48:*:*:All tests disabled on Navi48 + * alderlake:i915_pm:*:Power management tests broken + * + * Environment variable format (IGT_PLATFORM_SKIP_CONFIG): + * Same as config file, semicolon-separated entries: + * export IGT_PLATFORM_SKIP_CONFIG="navi48:*:*:Testing;navi10:amd_basic:*:Broken" + */ + +/* Maximum platform ranges per skip entry */ +#define MAX_PLATFORM_RANGES 4 + +/** + * enum skip_source - Source of skip rule + */ +enum skip_source { + SKIP_SOURCE_BUILTIN, /* From vendor built-in array */ + SKIP_SOURCE_CONFIG, /* From /etc/igt/platform_skip.conf */ + SKIP_SOURCE_ENV, /* From IGT_PLATFORM_SKIP_CONFIG */ + SKIP_SOURCE_NONE, /* Not skipped */ +}; + +/** + * struct platform_skip_entry - Generic skip rule entry + * + * Generic structure for skip rules. Vendor-specific data is stored + * in platform_data field and interpreted by vendor callbacks. + */ +struct platform_skip_entry { + const char *test_name; /* Test binary name or "*" for all */ + const char *subtest_glob; /* Subtest pattern (fnmatch) or "*" */ + const char *reason; /* Human-readable reason (required) */ + void *platform_data; /* Vendor-specific platform matching data */ +}; + +/** + * struct platform_filter_ops - Vendor-specific operations + * + * Callback structure that vendors implement to provide platform-specific + * filtering logic. This allows the core filtering framework to remain + * vendor-agnostic. + */ +struct platform_filter_ops { + /** @name: Vendor name (e.g., "amd", "intel") */ + + const char *name; + + /** @get_platform_name: Get current platform name */ + const char *(*get_platform_name)(const void *platform_info); + + /** @match_platform: Check if skip entry matches current platform */ + bool (*match_platform)(const void *platform_info, const void *platform_data); + + /** @parse_platform_config: Parse platform string from config file */ + bool (*parse_platform_config)(const char *platform_str, void **platform_data_out); + + /** @get_builtin_rules: Get vendor-specific built-in skip rules */ + const struct platform_skip_entry *(*get_builtin_rules)(int *count_out); + + /** @dump_platform_data: Dump platform_data for debugging (optional) */ + void (*dump_platform_data)(const void *platform_data); +}; + +bool igt_platform_filter_is_initialized(void); + +void igt_platform_filter_init(const struct platform_filter_ops *ops, + const void *platform_info); + +void igt_platform_require(const char *subtest_name); + +bool igt_platform_should_skip(const char *test_name, + const char *subtest_name, + enum skip_source *source, + const char **reason); + +void igt_platform_filter_dump(void); + +int igt_platform_filter_dump_to_file(const char *filename); + +#endif /* IGT_PLATFORM_FILTER_H */ diff --git a/lib/meson.build b/lib/meson.build index 3001b473e..1c04ee813 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -38,6 +38,7 @@ lib_sources = [ 'igt_params.c', 'igt_perf.c', 'igt_pipe_crc.c', + 'igt_platform_filter.c', 'igt_power.c', 'igt_primes.c', 'igt_pci.c', -- 2.43.0