From: <vitaly.prosyak@amd.com>
To: <igt-dev@lists.freedesktop.org>
Cc: "Vitaly Prosyak" <vitaly.prosyak@amd.com>,
"Kamil Konieczny" <kamil.konieczny@linux.intel.com>,
"Jani Nikula" <jani.nikula@linux.intel.com>,
"Jesse Zhang" <jesse.zhang@amd.com>,
"Christian König" <christian.koenig@amd.com>,
"Alex Deucher" <alexander.deucher@amd.com>,
"Krzysztof Karas" <krzysztof.karas@intel.com>
Subject: [PATCH 2/7] lib: Implement generic platform filtering framework
Date: Fri, 3 Jul 2026 10:08:22 -0400 [thread overview]
Message-ID: <20260703141115.69015-2-vitaly.prosyak@amd.com> (raw)
In-Reply-To: <20260703141115.69015-1-vitaly.prosyak@amd.com>
From: Vitaly Prosyak <vitaly.prosyak@amd.com>
Implement the vendor-agnostic platform filtering core that provides:
- Three-tier priority system:
1. Built-in rules (highest, vendor-specific, requires rebuild)
2. Config file /etc/igt/platform_skip.conf (no rebuild needed)
3. Environment variable IGT_PLATFORM_SKIP_CONFIG (runtime)
- Config file parsing with format: platform:test:subtest:reason
- Environment variable parsing (semicolon-separated entries)
- Wildcard/glob matching for test and subtest names
- igt_platform_require() integration with igt_skip()
- Dump functionality for debugging filter state
All state is held in struct platform_filter_context (no globals).
Vendor backends are accessed exclusively through platform_filter_ops
callbacks, keeping this code completely vendor-neutral.
v2: Address review feedback (2 comments from Kamil Konieczny, 3 from Krzysztof Karas):
- Added comprehensive kernel-doc to all 5 public API functions (Kamil Konieczny)
- Fixed comment style for section headers (Kamil Konieczny)
- Fixed parse_config_line() code duplication (Krzysztof Karas)
- Removed superfluous comments in entry_matches() (Krzysztof Karas)
- Re-added (void*) casts to free() calls - required to avoid const qualifier
warnings on some compilers, despite initial suggestion to remove them
- Added newlines before return statements (both reviewers)
Cc: Kamil Konieczny <kamil.konieczny@linux.intel.com>
Cc: Jani Nikula <jani.nikula@linux.intel.com>
Cc: Jesse Zhang <jesse.zhang@amd.com>
Cc: Christian König <christian.koenig@amd.com>
Cc: Alex Deucher <alexander.deucher@amd.com>
Cc: Krzysztof Karas <krzysztof.karas@intel.com>
Signed-off-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
Reviewed-by: Jesse Zhang <jesse.zhang@amd.com>
Change-Id: I0a6ce532c2ef9913e68c9a23c8b9e642443a367e
---
lib/igt_platform_filter.c | 579 ++++++++++++++++++++++++++++++++++++++
lib/meson.build | 1 +
2 files changed, 580 insertions(+)
create mode 100644 lib/igt_platform_filter.c
diff --git a/lib/igt_platform_filter.c b/lib/igt_platform_filter.c
new file mode 100644
index 000000000..5e2e7c744
--- /dev/null
+++ b/lib/igt_platform_filter.c
@@ -0,0 +1,579 @@
+// 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 */
+
+/**
+ * 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
+ */
+ 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");
+}
+
+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;
+ }
+ }
+
+
+/**
+ * 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.
+ */
+ /* 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;
+}
+
+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)) {
+
+/**
+ * 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.
+ */
+ 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");
+ }
+}
+
+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_platform_filter_dump_to_file:
+ * @filename: Path to output file
+ *
+ * Dump platform filtering configuration to a file.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+ 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");
+}
+
+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;
+}
diff --git a/lib/meson.build b/lib/meson.build
index d1289a5e0..ba0683995 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.54.0
next prev parent reply other threads:[~2026-07-03 14:11 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-03 14:08 [PATCH 1/7] lib: Add vendor-agnostic platform filtering interface vitaly.prosyak
2026-07-03 14:08 ` vitaly.prosyak [this message]
2026-07-03 14:08 ` [PATCH 3/7] lib/amdgpu: Add AMD platform filtering backend vitaly.prosyak
2026-07-03 14:08 ` [PATCH 4/7] lib: Add platform filter initialization check for automatic filtering vitaly.prosyak
2026-07-03 14:08 ` [PATCH 5/7] lib/igt_core: Enable automatic platform filtering in subtest execution vitaly.prosyak
2026-07-03 14:08 ` [PATCH 6/7] docs: Add comprehensive platform filtering documentation vitaly.prosyak
2026-07-03 14:08 ` [PATCH 7/7] tests/amdgpu: Integrate platform filtering into amd_basic vitaly.prosyak
2026-07-03 15:42 ` ✓ Xe.CI.BAT: success for series starting with [1/7] lib: Add vendor-agnostic platform filtering interface Patchwork
2026-07-03 15:59 ` ✓ i915.CI.BAT: " Patchwork
2026-07-04 2:47 ` ✓ Xe.CI.FULL: " Patchwork
2026-07-04 7:04 ` ✗ i915.CI.Full: failure " Patchwork
-- strict thread matches above, loose matches on Subject: below --
2026-06-30 3:23 [PATCH 1/7] " vitaly.prosyak
2026-06-30 3:23 ` [PATCH 2/7] lib: Implement generic platform filtering framework vitaly.prosyak
2026-07-01 14:38 ` Krzysztof Karas
2026-07-02 12:30 ` Kamil Konieczny
2026-07-02 17:25 ` Kamil Konieczny
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=20260703141115.69015-2-vitaly.prosyak@amd.com \
--to=vitaly.prosyak@amd.com \
--cc=alexander.deucher@amd.com \
--cc=christian.koenig@amd.com \
--cc=igt-dev@lists.freedesktop.org \
--cc=jani.nikula@linux.intel.com \
--cc=jesse.zhang@amd.com \
--cc=kamil.konieczny@linux.intel.com \
--cc=krzysztof.karas@intel.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