* [PATCH v3 i-g-t 01/10] lib/igt_sysfs_choice: Add helpers for sysfs enumerated choice attributes
2026-01-28 18:08 [PATCH v3 i-g-t 00/10] Xe SR-IOV admin scheduling helpers and test updates Marcin Bernatowicz
@ 2026-01-28 18:08 ` Marcin Bernatowicz
2026-01-29 8:19 ` Laguna, Lukasz
2026-01-28 18:08 ` [PATCH v3 i-g-t 02/10] lib/tests/igt_sysfs_choice: Add test coverage Marcin Bernatowicz
` (10 subsequent siblings)
11 siblings, 1 reply; 19+ messages in thread
From: Marcin Bernatowicz @ 2026-01-28 18:08 UTC (permalink / raw)
To: igt-dev
Cc: adam.miszczak, jakub1.kolakowski, lukasz.laguna, michal.wajdeczko,
Marcin Bernatowicz, Kamil Konieczny
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=y, Size: 14865 bytes --]
Introduce igt_sysfs_choice, a lightweight, fixed-size, no-malloc helper
for parsing and formatting sysfs "choice" attributes of the form:
"low [normal] high\n"
The helper provides parsing, lookup, formatting, mask conversion, and
intersection utilities for consistent handling of enumerated sysfs values.
Suggested-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
Cc: Adam Miszczak <adam.miszczak@linux.intel.com>
Cc: Jakub Kolakowski <jakub1.kolakowski@intel.com>
Cc: Kamil Konieczny <kamil.konieczny@linux.intel.com>
Cc: Lukasz Laguna <lukasz.laguna@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
---
v2:
- Corrected date
- Fix documentation formatting/description.
- Make igt_sysfs_choice_to_string() return error code instead of NULL.
- Use names_sz consistently.
- Make igt_sysfs_choice_format_mask() return error code instead of NULL.
Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
---
lib/igt_sysfs_choice.c | 439 +++++++++++++++++++++++++++++++++++++++++
lib/igt_sysfs_choice.h | 52 +++++
lib/meson.build | 1 +
3 files changed, 492 insertions(+)
create mode 100644 lib/igt_sysfs_choice.c
create mode 100644 lib/igt_sysfs_choice.h
diff --git a/lib/igt_sysfs_choice.c b/lib/igt_sysfs_choice.c
new file mode 100644
index 000000000..5ce2a2b70
--- /dev/null
+++ b/lib/igt_sysfs_choice.c
@@ -0,0 +1,439 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+#include "igt_sysfs_choice.h"
+#include <ctype.h>
+#include <errno.h>
+#include "igt_core.h"
+#include "igt_sysfs.h"
+
+#define IGT_SYSFS_CHOICE_MAX_LEN 256
+#define IGT_SYSFS_CHOICE_MAX_TOKENS 16
+
+/**
+ * igt_sysfs_choice_parse() - parse sysfs enumerated choice buffer
+ * @buf: NUL-terminated buffer with sysfs contents
+ * @choice: output descriptor, must be non-NULL (can be zeroed)
+ *
+ * Parses a sysfs enumerated choice buffer, e.g.:
+ *
+ * "low [normal] high\n"
+ *
+ * into a token list and the index of the selected token.
+ *
+ * Parsing rules:
+ * - tokens are separated by ASCII whitespace
+ * - exactly one token must be wrapped in '[' and ']'
+ * - surrounding '[' and ']' are stripped from the selected token
+ * - empty tokens are treated as malformed input
+ *
+ * On entry, any previous contents of @choice are freed.
+ *
+ * Returns:
+ * 0 on success,
+ * -EINVAL malformed format (no tokens, no selected token, multiple
+ * selected tokens, unterminated '[' or ']'),
+ * -E2BIG on too many tokens or too small choice buffer size.
+ */
+int igt_sysfs_choice_parse(const char *buf, struct igt_sysfs_choice *choice)
+{
+ char *p, *tok_start;
+ bool selected_seen = false;
+ size_t num_tokens = 0;
+ int n, selected = -1;
+ bool is_selected;
+
+ igt_assert(buf && choice);
+
+ memset(choice, 0, sizeof(*choice));
+ n = snprintf(choice->buf, sizeof(choice->buf), "%s", buf);
+ if (igt_debug_on(n < 0))
+ return -EINVAL;
+ if (igt_debug_on((size_t)n >= sizeof(choice->buf)))
+ return -E2BIG;
+
+ choice->num_tokens = 0;
+ choice->selected = -1;
+ p = choice->buf;
+
+ while (*p) {
+ /* skip leading whitespace */
+ while (*p && isspace((unsigned char)*p))
+ p++;
+ if (!*p)
+ break;
+
+ is_selected = false;
+ tok_start = p;
+
+ if (*p == '[') {
+ is_selected = true;
+ p++;
+ tok_start = p;
+
+ if (selected_seen) {
+ igt_debug("choice-parse: multiple [selected] tokens: \"%s\"\n",
+ choice->buf);
+ return -EINVAL;
+ }
+ selected_seen = true;
+ }
+
+ /* walk until ']' or whitespace */
+ while (*p && !isspace((unsigned char)*p) && *p != ']')
+ p++;
+
+ if (is_selected) {
+ if (*p != ']') {
+ igt_debug("choice-parse: unterminated '[' in: \"%s\"\n",
+ choice->buf);
+ return -EINVAL;
+ }
+ }
+
+ /* terminate token */
+ if (*p) {
+ *p = '\0';
+ p++;
+ }
+
+ if (!*tok_start) {
+ igt_debug("choice-parse: empty token in: \"%s\"\n",
+ choice->buf);
+ return -EINVAL;
+ }
+
+ if (num_tokens >= IGT_SYSFS_CHOICE_MAX_TOKENS) {
+ igt_debug("choice-parse: too many tokens (>%d) in: \"%s\"\n",
+ IGT_SYSFS_CHOICE_MAX_TOKENS, choice->buf);
+ return -E2BIG;
+ }
+
+ choice->tokens[num_tokens] = tok_start;
+ if (is_selected)
+ selected = (int)num_tokens;
+
+ num_tokens++;
+ }
+
+ if (!num_tokens) {
+ igt_debug("choice-parse: no tokens in string: \"%s\"\n",
+ choice->buf);
+ return -EINVAL;
+ }
+
+ if (selected < 0) {
+ igt_debug("choice-parse: missing selected token ([...]) in: \"%s\"\n",
+ choice->buf);
+ return -EINVAL;
+ }
+
+ choice->num_tokens = num_tokens;
+ choice->selected = selected;
+
+ return 0;
+}
+
+/**
+ * igt_sysfs_choice_read() - read and parse a sysfs enumerated choice attribute
+ * @dirfd: directory file descriptor of the sysfs node
+ * @attr: attribute name relative to @dirfd
+ * @choice: output descriptor, must be non-NULL
+ *
+ * Reads the given sysfs attribute into a temporary buffer and parses it.
+ *
+ * Returns:
+ * 0 on success,
+ * negative errno-style value on read or parse error.
+ */
+int igt_sysfs_choice_read(int dirfd, const char *attr,
+ struct igt_sysfs_choice *choice)
+{
+ char buf[IGT_SYSFS_CHOICE_MAX_LEN];
+ int len;
+
+ len = igt_sysfs_read(dirfd, attr, buf, sizeof(buf) - 1);
+ if (len < 0)
+ return len;
+
+ buf[len] = '\0';
+
+ return igt_sysfs_choice_parse(buf, choice);
+}
+
+/**
+ * igt_sysfs_choice_selected() - Return selected token string
+ * @choice: Parsed choice
+ *
+ * Returns:
+ * Pointer to the selected token string, or NULL if no valid selection.
+ */
+const char *igt_sysfs_choice_selected(const struct igt_sysfs_choice *choice)
+{
+ if (!choice || choice->selected < 0 ||
+ (size_t)choice->selected >= choice->num_tokens)
+ return NULL;
+
+ return choice->tokens[choice->selected];
+}
+
+/**
+ * igt_sysfs_choice_to_string() - Render a parsed choice into string
+ * @choice: Parsed choice (tokens[] + selected index)
+ * @buf: Output buffer for formatted string
+ * @buf_sz: Size of @buf in bytes
+ *
+ * Formats the given @choice into the string:
+ *
+ * "low [normal] high"
+ *
+ * Tokens are emitted in the order stored in @choice->tokens. The
+ * selected token (choice->selected) is wrapped in '[' and ']'.
+ *
+ * Returns:
+ * 0 on success,
+ * -EINVAL if arguments are invalid,
+ * -E2BIG if @buf_sz is too small.
+ */
+int igt_sysfs_choice_to_string(const struct igt_sysfs_choice *choice,
+ char *buf, size_t buf_sz)
+{
+ bool first = true;
+ size_t pos = 0;
+ int n;
+
+ if (!choice || !buf || !buf_sz)
+ return -EINVAL;
+
+ buf[0] = '\0';
+
+ for (size_t i = 0; i < choice->num_tokens; i++) {
+ const char *name = choice->tokens[i];
+ bool is_selected = (choice->selected == (int)i);
+
+ if (!name)
+ continue;
+
+ n = snprintf(buf + pos, buf_sz - pos,
+ "%s%s%s%s",
+ first ? "" : " ",
+ is_selected ? "[" : "",
+ name,
+ is_selected ? "]" : "");
+
+ if (n < 0)
+ return -EINVAL;
+ if ((size_t)n >= buf_sz - pos)
+ return -E2BIG;
+
+ pos += (size_t)n;
+ first = false;
+ }
+
+ return 0;
+}
+
+/**
+ * igt_sysfs_choice_find() - find token index by name
+ * @choice: parsed choice struct
+ * @token: token to look for (plain name, without '[' / ']')
+ *
+ * Performs a case-sensitive comparison of @token against entries in
+ * @choice->tokens.
+ *
+ * Returns:
+ * index in [0..choice->num_tokens-1] on match,
+ * -1 if @token is not present or @choice/@token is NULL.
+ */
+int igt_sysfs_choice_find(const struct igt_sysfs_choice *choice,
+ const char *token)
+{
+ if (!choice || !token)
+ return -1;
+
+ for (size_t i = 0; i < choice->num_tokens; i++)
+ if (!strcmp(choice->tokens[i], token))
+ return (int)i;
+
+ return -1;
+}
+
+/**
+ * igt_sysfs_choice_to_mask() - map parsed tokens to bitmask + selection
+ * @choice: parsed choice struct
+ * @names: array of known token names
+ * @names_sz: number of elements in @names
+ * @mask: output bitmask of supported names
+ * @selected_idx: output index of selected token in @names, or -1 if selected
+ * token is not among @names
+ *
+ * Builds a bitmask of known tokens present in @choice and identifies the
+ * selected token, if it matches one of @names.
+ *
+ * Unknown tokens do not cause an error; they are ignored and not
+ * reflected in @mask. This keeps the API "loose": tests can still
+ * validate required choices while tolerating additional values.
+ *
+ * Returns:
+ * 0 on success,
+ * -EINVAL on bad input parameters.
+ */
+int igt_sysfs_choice_to_mask(const struct igt_sysfs_choice *choice,
+ const char * const *names, size_t names_sz,
+ unsigned int *mask, int *selected_idx)
+{
+ unsigned int m = 0;
+ int sel = -1, idx;
+
+ if (!choice || !names || !mask)
+ return -EINVAL;
+
+ for (size_t i = 0; i < names_sz; i++) {
+ const char *name = names[i];
+
+ if (!name)
+ continue;
+
+ idx = igt_sysfs_choice_find(choice, name);
+ if (idx >= 0) {
+ m |= 1u << i;
+ if (idx == choice->selected)
+ sel = (int)i;
+ }
+ }
+
+ *mask = m;
+ if (selected_idx)
+ *selected_idx = sel;
+
+ return 0;
+}
+
+/**
+ * igt_sysfs_choice_format_mask() - Format a bitmask as a space-separated list of names
+ * @buf: Output buffer
+ * @buf_sz: Size of @buf in bytes
+ * @names: Array of token names indexed by bit position
+ * @names_sz: Number of elements in @names
+ * @mask: Bitmask of available tokens
+ * @selected_idx: Index to highlight with brackets, or <0 for none
+ *
+ * Builds a space-separated list of all bits set in @mask, mapping bit positions
+ * to names in @names. If @selected_idx >= 0 and that bit is set, the token is
+ * wrapped in brackets, e.g. "low [normal] high".
+ *
+ * This function is best-effort by design:
+ * - If names[i] is NULL, it is formatted as "?".
+ * - Bits beyond @names_sz are ignored.
+ * Empty @mask results in an empty string.
+ *
+ * Returns:
+ * 0 on success,
+ * -EINVAL on invalid arguments,
+ * -E2BIG if @buf_sz is too small.
+ */
+int igt_sysfs_choice_format_mask(char *buf, size_t buf_sz,
+ const char *const *names,
+ size_t names_sz,
+ unsigned int mask,
+ int selected_idx)
+{
+ bool first = true;
+ size_t pos = 0;
+
+ if (!buf || !buf_sz || !names || !names_sz)
+ return -EINVAL;
+
+ buf[0] = '\0';
+
+ for (size_t idx = 0; idx < names_sz && mask; idx++) {
+ int n;
+ const char *name;
+ bool highlight;
+
+ if (!(mask & 1u)) {
+ mask >>= 1;
+ continue;
+ }
+
+ name = names[idx] ?: "?";
+ highlight = ((int)idx == selected_idx);
+ n = snprintf(buf + pos, buf_sz - pos, "%s%s%s%s",
+ first ? "" : " ",
+ highlight ? "[" : "",
+ name,
+ highlight ? "]" : "");
+ if (n < 0)
+ return -EINVAL;
+ if ((size_t)n >= buf_sz - pos)
+ return -E2BIG;
+
+ pos += (size_t)n;
+ first = false;
+ mask >>= 1;
+ }
+
+ return 0;
+}
+
+/**
+ * igt_sysfs_choice_intersect() - Restrict a choice set to tokens common with another
+ * @dst: Choice to be updated in place
+ * @other: Choice providing the allowed tokens
+ *
+ * Computes the intersection of the token sets in @dst and @other.
+ * The resulting @dst contains only tokens that appear in both choices,
+ * preserving their original order from @dst.
+ *
+ * If the previously selected token in @dst is still present after
+ * intersection, its index is updated accordingly. If it is not present,
+ * @dst->selected is set to -1.
+ *
+ * Returns:
+ * * 0 - success
+ * * -EINVAL - invalid arguments
+ * * -ENOENT - no common tokens
+ */
+int igt_sysfs_choice_intersect(struct igt_sysfs_choice *dst,
+ const struct igt_sysfs_choice *other)
+{
+ char *new_tokens[IGT_SYSFS_CHOICE_MAX_TOKENS];
+ const char *selected_name;
+ int new_selected = -1;
+ size_t new_n = 0;
+
+ if (!dst || !other)
+ return -EINVAL;
+
+ selected_name = (dst->selected >= 0 && dst->selected < dst->num_tokens) ?
+ dst->tokens[dst->selected] : NULL;
+
+ for (size_t i = 0; i < dst->num_tokens; i++) {
+ char *tok = dst->tokens[i];
+
+ if (igt_sysfs_choice_find(other, tok) < 0)
+ continue;
+
+ new_tokens[new_n] = tok;
+
+ if (selected_name && !strcmp(tok, selected_name))
+ new_selected = (int)new_n;
+
+ new_n++;
+ }
+
+ if (!new_n) {
+ dst->num_tokens = 0;
+ dst->selected = -1;
+ return -ENOENT;
+ }
+
+ for (size_t i = 0; i < new_n; i++)
+ dst->tokens[i] = new_tokens[i];
+
+ dst->num_tokens = new_n;
+ dst->selected = new_selected;
+
+ return 0;
+}
diff --git a/lib/igt_sysfs_choice.h b/lib/igt_sysfs_choice.h
new file mode 100644
index 000000000..b354c774a
--- /dev/null
+++ b/lib/igt_sysfs_choice.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+#ifndef __IGT_SYSFS_CHOICE_H__
+#define __IGT_SYSFS_CHOICE_H__
+
+#include <stddef.h>
+#include <stdbool.h>
+
+#define IGT_SYSFS_CHOICE_MAX_LEN 256
+#define IGT_SYSFS_CHOICE_MAX_TOKENS 16
+
+/**
+ * struct igt_sysfs_choice - parsed sysfs enumerated choice attribute
+ * @tokens: array of token strings
+ * @num_tokens: number of entries in @tokens
+ * @selected: index of the active token in @tokens, or -1 if invalid
+ *
+ * This struct represents a sysfs enumerated choice attribute, for example:
+ *
+ * "low [normal] high\n"
+ *
+ * After parsing, @tokens point to "low", "normal", "high" and
+ * @selected will be 1 (the index of "normal").
+ */
+struct igt_sysfs_choice {
+ char buf[IGT_SYSFS_CHOICE_MAX_LEN];
+ char *tokens[IGT_SYSFS_CHOICE_MAX_TOKENS];
+ size_t num_tokens;
+ int selected; /* index into tokens[], or -1 */
+};
+
+int igt_sysfs_choice_parse(const char *buf, struct igt_sysfs_choice *choice);
+int igt_sysfs_choice_read(int dirfd, const char *attr,
+ struct igt_sysfs_choice *choice);
+const char *igt_sysfs_choice_selected(const struct igt_sysfs_choice *choice);
+int igt_sysfs_choice_to_string(const struct igt_sysfs_choice *choice,
+ char *buf, size_t buf_sz);
+int igt_sysfs_choice_find(const struct igt_sysfs_choice *choice,
+ const char *token);
+int igt_sysfs_choice_to_mask(const struct igt_sysfs_choice *choice,
+ const char *const *names, size_t names_sz,
+ unsigned int *mask, int *selected_idx);
+int igt_sysfs_choice_format_mask(char *buf, size_t buf_sz,
+ const char *const *names,
+ size_t names_sz, unsigned int mask,
+ int selected_idx);
+int igt_sysfs_choice_intersect(struct igt_sysfs_choice *dst,
+ const struct igt_sysfs_choice *other);
+
+#endif /* __IGT_SYSFS_CHOICE_H__ */
diff --git a/lib/meson.build b/lib/meson.build
index 1a569ba52..83569e8d2 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -44,6 +44,7 @@ lib_sources = [
'igt_stats.c',
'igt_syncobj.c',
'igt_sysfs.c',
+ 'igt_sysfs_choice.c',
'igt_sysrq.c',
'igt_taints.c',
'igt_thread.c',
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* Re: [PATCH v3 i-g-t 01/10] lib/igt_sysfs_choice: Add helpers for sysfs enumerated choice attributes
2026-01-28 18:08 ` [PATCH v3 i-g-t 01/10] lib/igt_sysfs_choice: Add helpers for sysfs enumerated choice attributes Marcin Bernatowicz
@ 2026-01-29 8:19 ` Laguna, Lukasz
0 siblings, 0 replies; 19+ messages in thread
From: Laguna, Lukasz @ 2026-01-29 8:19 UTC (permalink / raw)
To: Marcin Bernatowicz, igt-dev
Cc: adam.miszczak, jakub1.kolakowski, michal.wajdeczko,
Kamil Konieczny
On 1/28/2026 19:08, Marcin Bernatowicz wrote:
> Introduce igt_sysfs_choice, a lightweight, fixed-size, no-malloc helper
> for parsing and formatting sysfs "choice" attributes of the form:
>
> "low [normal] high\n"
>
> The helper provides parsing, lookup, formatting, mask conversion, and
> intersection utilities for consistent handling of enumerated sysfs values.
>
> Suggested-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
> Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
> Cc: Adam Miszczak <adam.miszczak@linux.intel.com>
> Cc: Jakub Kolakowski <jakub1.kolakowski@intel.com>
> Cc: Kamil Konieczny <kamil.konieczny@linux.intel.com>
> Cc: Lukasz Laguna <lukasz.laguna@intel.com>
Reviewed-by: Lukasz Laguna <lukasz.laguna@intel.com>
> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
>
> ---
> v2:
> - Corrected date
> - Fix documentation formatting/description.
> - Make igt_sysfs_choice_to_string() return error code instead of NULL.
> - Use names_sz consistently.
> - Make igt_sysfs_choice_format_mask() return error code instead of NULL.
>
> Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
> ---
> lib/igt_sysfs_choice.c | 439 +++++++++++++++++++++++++++++++++++++++++
> lib/igt_sysfs_choice.h | 52 +++++
> lib/meson.build | 1 +
> 3 files changed, 492 insertions(+)
> create mode 100644 lib/igt_sysfs_choice.c
> create mode 100644 lib/igt_sysfs_choice.h
>
> diff --git a/lib/igt_sysfs_choice.c b/lib/igt_sysfs_choice.c
> new file mode 100644
> index 000000000..5ce2a2b70
> --- /dev/null
> +++ b/lib/igt_sysfs_choice.c
> @@ -0,0 +1,439 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2026 Intel Corporation
> + */
> +#include "igt_sysfs_choice.h"
> +#include <ctype.h>
> +#include <errno.h>
> +#include "igt_core.h"
> +#include "igt_sysfs.h"
> +
> +#define IGT_SYSFS_CHOICE_MAX_LEN 256
> +#define IGT_SYSFS_CHOICE_MAX_TOKENS 16
> +
> +/**
> + * igt_sysfs_choice_parse() - parse sysfs enumerated choice buffer
> + * @buf: NUL-terminated buffer with sysfs contents
> + * @choice: output descriptor, must be non-NULL (can be zeroed)
> + *
> + * Parses a sysfs enumerated choice buffer, e.g.:
> + *
> + * "low [normal] high\n"
> + *
> + * into a token list and the index of the selected token.
> + *
> + * Parsing rules:
> + * - tokens are separated by ASCII whitespace
> + * - exactly one token must be wrapped in '[' and ']'
> + * - surrounding '[' and ']' are stripped from the selected token
> + * - empty tokens are treated as malformed input
> + *
> + * On entry, any previous contents of @choice are freed.
> + *
> + * Returns:
> + * 0 on success,
> + * -EINVAL malformed format (no tokens, no selected token, multiple
> + * selected tokens, unterminated '[' or ']'),
> + * -E2BIG on too many tokens or too small choice buffer size.
> + */
> +int igt_sysfs_choice_parse(const char *buf, struct igt_sysfs_choice *choice)
> +{
> + char *p, *tok_start;
> + bool selected_seen = false;
> + size_t num_tokens = 0;
> + int n, selected = -1;
> + bool is_selected;
> +
> + igt_assert(buf && choice);
> +
> + memset(choice, 0, sizeof(*choice));
> + n = snprintf(choice->buf, sizeof(choice->buf), "%s", buf);
> + if (igt_debug_on(n < 0))
> + return -EINVAL;
> + if (igt_debug_on((size_t)n >= sizeof(choice->buf)))
> + return -E2BIG;
> +
> + choice->num_tokens = 0;
> + choice->selected = -1;
> + p = choice->buf;
> +
> + while (*p) {
> + /* skip leading whitespace */
> + while (*p && isspace((unsigned char)*p))
> + p++;
> + if (!*p)
> + break;
> +
> + is_selected = false;
> + tok_start = p;
> +
> + if (*p == '[') {
> + is_selected = true;
> + p++;
> + tok_start = p;
> +
> + if (selected_seen) {
> + igt_debug("choice-parse: multiple [selected] tokens: \"%s\"\n",
> + choice->buf);
> + return -EINVAL;
> + }
> + selected_seen = true;
> + }
> +
> + /* walk until ']' or whitespace */
> + while (*p && !isspace((unsigned char)*p) && *p != ']')
> + p++;
> +
> + if (is_selected) {
> + if (*p != ']') {
> + igt_debug("choice-parse: unterminated '[' in: \"%s\"\n",
> + choice->buf);
> + return -EINVAL;
> + }
> + }
> +
> + /* terminate token */
> + if (*p) {
> + *p = '\0';
> + p++;
> + }
> +
> + if (!*tok_start) {
> + igt_debug("choice-parse: empty token in: \"%s\"\n",
> + choice->buf);
> + return -EINVAL;
> + }
> +
> + if (num_tokens >= IGT_SYSFS_CHOICE_MAX_TOKENS) {
> + igt_debug("choice-parse: too many tokens (>%d) in: \"%s\"\n",
> + IGT_SYSFS_CHOICE_MAX_TOKENS, choice->buf);
> + return -E2BIG;
> + }
> +
> + choice->tokens[num_tokens] = tok_start;
> + if (is_selected)
> + selected = (int)num_tokens;
> +
> + num_tokens++;
> + }
> +
> + if (!num_tokens) {
> + igt_debug("choice-parse: no tokens in string: \"%s\"\n",
> + choice->buf);
> + return -EINVAL;
> + }
> +
> + if (selected < 0) {
> + igt_debug("choice-parse: missing selected token ([...]) in: \"%s\"\n",
> + choice->buf);
> + return -EINVAL;
> + }
> +
> + choice->num_tokens = num_tokens;
> + choice->selected = selected;
> +
> + return 0;
> +}
> +
> +/**
> + * igt_sysfs_choice_read() - read and parse a sysfs enumerated choice attribute
> + * @dirfd: directory file descriptor of the sysfs node
> + * @attr: attribute name relative to @dirfd
> + * @choice: output descriptor, must be non-NULL
> + *
> + * Reads the given sysfs attribute into a temporary buffer and parses it.
> + *
> + * Returns:
> + * 0 on success,
> + * negative errno-style value on read or parse error.
> + */
> +int igt_sysfs_choice_read(int dirfd, const char *attr,
> + struct igt_sysfs_choice *choice)
> +{
> + char buf[IGT_SYSFS_CHOICE_MAX_LEN];
> + int len;
> +
> + len = igt_sysfs_read(dirfd, attr, buf, sizeof(buf) - 1);
> + if (len < 0)
> + return len;
> +
> + buf[len] = '\0';
> +
> + return igt_sysfs_choice_parse(buf, choice);
> +}
> +
> +/**
> + * igt_sysfs_choice_selected() - Return selected token string
> + * @choice: Parsed choice
> + *
> + * Returns:
> + * Pointer to the selected token string, or NULL if no valid selection.
> + */
> +const char *igt_sysfs_choice_selected(const struct igt_sysfs_choice *choice)
> +{
> + if (!choice || choice->selected < 0 ||
> + (size_t)choice->selected >= choice->num_tokens)
> + return NULL;
> +
> + return choice->tokens[choice->selected];
> +}
> +
> +/**
> + * igt_sysfs_choice_to_string() - Render a parsed choice into string
> + * @choice: Parsed choice (tokens[] + selected index)
> + * @buf: Output buffer for formatted string
> + * @buf_sz: Size of @buf in bytes
> + *
> + * Formats the given @choice into the string:
> + *
> + * "low [normal] high"
> + *
> + * Tokens are emitted in the order stored in @choice->tokens. The
> + * selected token (choice->selected) is wrapped in '[' and ']'.
> + *
> + * Returns:
> + * 0 on success,
> + * -EINVAL if arguments are invalid,
> + * -E2BIG if @buf_sz is too small.
> + */
> +int igt_sysfs_choice_to_string(const struct igt_sysfs_choice *choice,
> + char *buf, size_t buf_sz)
> +{
> + bool first = true;
> + size_t pos = 0;
> + int n;
> +
> + if (!choice || !buf || !buf_sz)
> + return -EINVAL;
> +
> + buf[0] = '\0';
> +
> + for (size_t i = 0; i < choice->num_tokens; i++) {
> + const char *name = choice->tokens[i];
> + bool is_selected = (choice->selected == (int)i);
> +
> + if (!name)
> + continue;
> +
> + n = snprintf(buf + pos, buf_sz - pos,
> + "%s%s%s%s",
> + first ? "" : " ",
> + is_selected ? "[" : "",
> + name,
> + is_selected ? "]" : "");
> +
> + if (n < 0)
> + return -EINVAL;
> + if ((size_t)n >= buf_sz - pos)
> + return -E2BIG;
> +
> + pos += (size_t)n;
> + first = false;
> + }
> +
> + return 0;
> +}
> +
> +/**
> + * igt_sysfs_choice_find() - find token index by name
> + * @choice: parsed choice struct
> + * @token: token to look for (plain name, without '[' / ']')
> + *
> + * Performs a case-sensitive comparison of @token against entries in
> + * @choice->tokens.
> + *
> + * Returns:
> + * index in [0..choice->num_tokens-1] on match,
> + * -1 if @token is not present or @choice/@token is NULL.
> + */
> +int igt_sysfs_choice_find(const struct igt_sysfs_choice *choice,
> + const char *token)
> +{
> + if (!choice || !token)
> + return -1;
> +
> + for (size_t i = 0; i < choice->num_tokens; i++)
> + if (!strcmp(choice->tokens[i], token))
> + return (int)i;
> +
> + return -1;
> +}
> +
> +/**
> + * igt_sysfs_choice_to_mask() - map parsed tokens to bitmask + selection
> + * @choice: parsed choice struct
> + * @names: array of known token names
> + * @names_sz: number of elements in @names
> + * @mask: output bitmask of supported names
> + * @selected_idx: output index of selected token in @names, or -1 if selected
> + * token is not among @names
> + *
> + * Builds a bitmask of known tokens present in @choice and identifies the
> + * selected token, if it matches one of @names.
> + *
> + * Unknown tokens do not cause an error; they are ignored and not
> + * reflected in @mask. This keeps the API "loose": tests can still
> + * validate required choices while tolerating additional values.
> + *
> + * Returns:
> + * 0 on success,
> + * -EINVAL on bad input parameters.
> + */
> +int igt_sysfs_choice_to_mask(const struct igt_sysfs_choice *choice,
> + const char * const *names, size_t names_sz,
> + unsigned int *mask, int *selected_idx)
> +{
> + unsigned int m = 0;
> + int sel = -1, idx;
> +
> + if (!choice || !names || !mask)
> + return -EINVAL;
> +
> + for (size_t i = 0; i < names_sz; i++) {
> + const char *name = names[i];
> +
> + if (!name)
> + continue;
> +
> + idx = igt_sysfs_choice_find(choice, name);
> + if (idx >= 0) {
> + m |= 1u << i;
> + if (idx == choice->selected)
> + sel = (int)i;
> + }
> + }
> +
> + *mask = m;
> + if (selected_idx)
> + *selected_idx = sel;
> +
> + return 0;
> +}
> +
> +/**
> + * igt_sysfs_choice_format_mask() - Format a bitmask as a space-separated list of names
> + * @buf: Output buffer
> + * @buf_sz: Size of @buf in bytes
> + * @names: Array of token names indexed by bit position
> + * @names_sz: Number of elements in @names
> + * @mask: Bitmask of available tokens
> + * @selected_idx: Index to highlight with brackets, or <0 for none
> + *
> + * Builds a space-separated list of all bits set in @mask, mapping bit positions
> + * to names in @names. If @selected_idx >= 0 and that bit is set, the token is
> + * wrapped in brackets, e.g. "low [normal] high".
> + *
> + * This function is best-effort by design:
> + * - If names[i] is NULL, it is formatted as "?".
> + * - Bits beyond @names_sz are ignored.
> + * Empty @mask results in an empty string.
> + *
> + * Returns:
> + * 0 on success,
> + * -EINVAL on invalid arguments,
> + * -E2BIG if @buf_sz is too small.
> + */
> +int igt_sysfs_choice_format_mask(char *buf, size_t buf_sz,
> + const char *const *names,
> + size_t names_sz,
> + unsigned int mask,
> + int selected_idx)
> +{
> + bool first = true;
> + size_t pos = 0;
> +
> + if (!buf || !buf_sz || !names || !names_sz)
> + return -EINVAL;
> +
> + buf[0] = '\0';
> +
> + for (size_t idx = 0; idx < names_sz && mask; idx++) {
> + int n;
> + const char *name;
> + bool highlight;
> +
> + if (!(mask & 1u)) {
> + mask >>= 1;
> + continue;
> + }
> +
> + name = names[idx] ?: "?";
> + highlight = ((int)idx == selected_idx);
> + n = snprintf(buf + pos, buf_sz - pos, "%s%s%s%s",
> + first ? "" : " ",
> + highlight ? "[" : "",
> + name,
> + highlight ? "]" : "");
> + if (n < 0)
> + return -EINVAL;
> + if ((size_t)n >= buf_sz - pos)
> + return -E2BIG;
> +
> + pos += (size_t)n;
> + first = false;
> + mask >>= 1;
> + }
> +
> + return 0;
> +}
> +
> +/**
> + * igt_sysfs_choice_intersect() - Restrict a choice set to tokens common with another
> + * @dst: Choice to be updated in place
> + * @other: Choice providing the allowed tokens
> + *
> + * Computes the intersection of the token sets in @dst and @other.
> + * The resulting @dst contains only tokens that appear in both choices,
> + * preserving their original order from @dst.
> + *
> + * If the previously selected token in @dst is still present after
> + * intersection, its index is updated accordingly. If it is not present,
> + * @dst->selected is set to -1.
> + *
> + * Returns:
> + * * 0 - success
> + * * -EINVAL - invalid arguments
> + * * -ENOENT - no common tokens
> + */
> +int igt_sysfs_choice_intersect(struct igt_sysfs_choice *dst,
> + const struct igt_sysfs_choice *other)
> +{
> + char *new_tokens[IGT_SYSFS_CHOICE_MAX_TOKENS];
> + const char *selected_name;
> + int new_selected = -1;
> + size_t new_n = 0;
> +
> + if (!dst || !other)
> + return -EINVAL;
> +
> + selected_name = (dst->selected >= 0 && dst->selected < dst->num_tokens) ?
> + dst->tokens[dst->selected] : NULL;
> +
> + for (size_t i = 0; i < dst->num_tokens; i++) {
> + char *tok = dst->tokens[i];
> +
> + if (igt_sysfs_choice_find(other, tok) < 0)
> + continue;
> +
> + new_tokens[new_n] = tok;
> +
> + if (selected_name && !strcmp(tok, selected_name))
> + new_selected = (int)new_n;
> +
> + new_n++;
> + }
> +
> + if (!new_n) {
> + dst->num_tokens = 0;
> + dst->selected = -1;
> + return -ENOENT;
> + }
> +
> + for (size_t i = 0; i < new_n; i++)
> + dst->tokens[i] = new_tokens[i];
> +
> + dst->num_tokens = new_n;
> + dst->selected = new_selected;
> +
> + return 0;
> +}
> diff --git a/lib/igt_sysfs_choice.h b/lib/igt_sysfs_choice.h
> new file mode 100644
> index 000000000..b354c774a
> --- /dev/null
> +++ b/lib/igt_sysfs_choice.h
> @@ -0,0 +1,52 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2026 Intel Corporation
> + */
> +#ifndef __IGT_SYSFS_CHOICE_H__
> +#define __IGT_SYSFS_CHOICE_H__
> +
> +#include <stddef.h>
> +#include <stdbool.h>
> +
> +#define IGT_SYSFS_CHOICE_MAX_LEN 256
> +#define IGT_SYSFS_CHOICE_MAX_TOKENS 16
> +
> +/**
> + * struct igt_sysfs_choice - parsed sysfs enumerated choice attribute
> + * @tokens: array of token strings
> + * @num_tokens: number of entries in @tokens
> + * @selected: index of the active token in @tokens, or -1 if invalid
> + *
> + * This struct represents a sysfs enumerated choice attribute, for example:
> + *
> + * "low [normal] high\n"
> + *
> + * After parsing, @tokens point to "low", "normal", "high" and
> + * @selected will be 1 (the index of "normal").
> + */
> +struct igt_sysfs_choice {
> + char buf[IGT_SYSFS_CHOICE_MAX_LEN];
> + char *tokens[IGT_SYSFS_CHOICE_MAX_TOKENS];
> + size_t num_tokens;
> + int selected; /* index into tokens[], or -1 */
> +};
> +
> +int igt_sysfs_choice_parse(const char *buf, struct igt_sysfs_choice *choice);
> +int igt_sysfs_choice_read(int dirfd, const char *attr,
> + struct igt_sysfs_choice *choice);
> +const char *igt_sysfs_choice_selected(const struct igt_sysfs_choice *choice);
> +int igt_sysfs_choice_to_string(const struct igt_sysfs_choice *choice,
> + char *buf, size_t buf_sz);
> +int igt_sysfs_choice_find(const struct igt_sysfs_choice *choice,
> + const char *token);
> +int igt_sysfs_choice_to_mask(const struct igt_sysfs_choice *choice,
> + const char *const *names, size_t names_sz,
> + unsigned int *mask, int *selected_idx);
> +int igt_sysfs_choice_format_mask(char *buf, size_t buf_sz,
> + const char *const *names,
> + size_t names_sz, unsigned int mask,
> + int selected_idx);
> +int igt_sysfs_choice_intersect(struct igt_sysfs_choice *dst,
> + const struct igt_sysfs_choice *other);
> +
> +#endif /* __IGT_SYSFS_CHOICE_H__ */
> diff --git a/lib/meson.build b/lib/meson.build
> index 1a569ba52..83569e8d2 100644
> --- a/lib/meson.build
> +++ b/lib/meson.build
> @@ -44,6 +44,7 @@ lib_sources = [
> 'igt_stats.c',
> 'igt_syncobj.c',
> 'igt_sysfs.c',
> + 'igt_sysfs_choice.c',
> 'igt_sysrq.c',
> 'igt_taints.c',
> 'igt_thread.c',
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 i-g-t 02/10] lib/tests/igt_sysfs_choice: Add test coverage
2026-01-28 18:08 [PATCH v3 i-g-t 00/10] Xe SR-IOV admin scheduling helpers and test updates Marcin Bernatowicz
2026-01-28 18:08 ` [PATCH v3 i-g-t 01/10] lib/igt_sysfs_choice: Add helpers for sysfs enumerated choice attributes Marcin Bernatowicz
@ 2026-01-28 18:08 ` Marcin Bernatowicz
2026-01-29 8:19 ` Laguna, Lukasz
2026-01-28 18:08 ` [PATCH v3 i-g-t 03/10] lib/xe/xe_sriov_provisioning: Add string conversion helpers for scheduling priority Marcin Bernatowicz
` (9 subsequent siblings)
11 siblings, 1 reply; 19+ messages in thread
From: Marcin Bernatowicz @ 2026-01-28 18:08 UTC (permalink / raw)
To: igt-dev
Cc: adam.miszczak, jakub1.kolakowski, lukasz.laguna, michal.wajdeczko,
Marcin Bernatowicz, Kamil Konieczny
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=y, Size: 10866 bytes --]
Add unit tests exercising parsing, selection rules, intersection,
round-trip formatting, and mask conversion for igt_sysfs_choice.
Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
Cc: Adam Miszczak <adam.miszczak@linux.intel.com>
Cc: Jakub Kolakowski <jakub1.kolakowski@intel.com>
Cc: Kamil Konieczny <kamil.konieczny@linux.intel.com>
Cc: Lukasz Laguna <lukasz.laguna@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
---
v2:
- Align igt_simple_main() usage with upstream changes.
- Corrected date, improved assert messages.
- Use BIT() instead of (1u << n) for sysfs choice masks.
- Adjust test for igt_sysfs_choice_to_string() returning error code.
- Adjust test for igt_sysfs_choice_format_mask() returning error code.
Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
---
lib/tests/igt_sysfs_choice.c | 388 +++++++++++++++++++++++++++++++++++
lib/tests/meson.build | 1 +
2 files changed, 389 insertions(+)
create mode 100644 lib/tests/igt_sysfs_choice.c
diff --git a/lib/tests/igt_sysfs_choice.c b/lib/tests/igt_sysfs_choice.c
new file mode 100644
index 000000000..c573a0dff
--- /dev/null
+++ b/lib/tests/igt_sysfs_choice.c
@@ -0,0 +1,388 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+#include <errno.h>
+#include "drmtest.h"
+#include "igt_core.h"
+#include "intel_chipset.h"
+#include "igt_sysfs_choice.h"
+
+static void assert_token(const struct igt_sysfs_choice *c,
+ size_t idx, const char *expected)
+{
+ igt_assert_f(idx < c->num_tokens,
+ "token index %zu out of range (num_tokens=%zu)\n",
+ idx, c->num_tokens);
+ igt_assert(c->tokens[idx]);
+ igt_assert_f(!strcmp(c->tokens[idx], expected),
+ "token[%zu] mismatch: got='%s' expected='%s'\n",
+ idx, c->tokens[idx], expected);
+}
+
+static void parse_ok(const char *str, struct igt_sysfs_choice *choice)
+{
+ int ret;
+
+ ret = igt_sysfs_choice_parse(str, choice);
+ igt_assert_f(ret == 0, "parse(\"%s\") failed: %d\n", str, ret);
+}
+
+static void test_parse_basic_first_selected(void)
+{
+ struct igt_sysfs_choice c;
+
+ parse_ok("[low] normal high\n", &c);
+
+ igt_assert_eq(c.num_tokens, 3);
+ assert_token(&c, 0, "low");
+ assert_token(&c, 1, "normal");
+ assert_token(&c, 2, "high");
+
+ igt_assert_eq(c.selected, 0);
+}
+
+static void test_parse_middle_selected_whitespace(void)
+{
+ struct igt_sysfs_choice c;
+
+ parse_ok(" low [normal] high \n", &c);
+
+ igt_assert_eq(c.num_tokens, 3);
+ assert_token(&c, 0, "low");
+ assert_token(&c, 1, "normal");
+ assert_token(&c, 2, "high");
+
+ igt_assert_eq(c.selected, 1);
+}
+
+static void test_parse_single_token(void)
+{
+ struct igt_sysfs_choice c;
+
+ parse_ok("[only]\n", &c);
+
+ igt_assert_eq(c.num_tokens, 1);
+ assert_token(&c, 0, "only");
+ igt_assert_eq(c.selected, 0);
+}
+
+static void test_parse_error_missing_selected(void)
+{
+ struct igt_sysfs_choice c;
+ int ret;
+
+ ret = igt_sysfs_choice_parse("low normal high\n", &c);
+ igt_assert_eq(ret, -EINVAL);
+}
+
+static void test_parse_error_multiple_selected(void)
+{
+ struct igt_sysfs_choice c;
+ int ret;
+
+ ret = igt_sysfs_choice_parse("[low] [normal] high\n", &c);
+ igt_assert_eq(ret, -EINVAL);
+
+ ret = igt_sysfs_choice_parse("low [normal] [high]\n", &c);
+ igt_assert_eq(ret, -EINVAL);
+}
+
+static void test_parse_error_unterminated_bracket(void)
+{
+ struct igt_sysfs_choice c;
+ int ret;
+
+ ret = igt_sysfs_choice_parse("[low normal high\n", &c);
+ igt_assert_eq(ret, -EINVAL);
+
+ ret = igt_sysfs_choice_parse("low [normal high]\n", &c);
+ igt_assert_eq(ret, -EINVAL);
+}
+
+static void test_parse_error_too_many_tokens(void)
+{
+ struct igt_sysfs_choice c;
+ char buf[512];
+ size_t i;
+ int len = 0;
+ int ret;
+
+ /*
+ * Build a line with (IGT_SYSFS_CHOICE_MAX_TOKENS + 1) tokens:
+ * "[t0] t1 t2 ... tN"
+ */
+ len += snprintf(buf + len, sizeof(buf) - len, "[t0]");
+ for (i = 1; i < IGT_SYSFS_CHOICE_MAX_TOKENS + 1 && len < (int)sizeof(buf); i++)
+ len += snprintf(buf + len, sizeof(buf) - len, " t%zu", i);
+ len += snprintf(buf + len, sizeof(buf) - len, "\n");
+
+ ret = igt_sysfs_choice_parse(buf, &c);
+ igt_assert_eq(ret, -E2BIG);
+}
+
+static void test_selected_basic(void)
+{
+ struct igt_sysfs_choice c;
+ const char *sel;
+
+ /* selected at position 0 */
+ parse_ok("[low] normal high\n", &c);
+ sel = igt_sysfs_choice_selected(&c);
+ igt_assert(sel);
+ igt_assert(!strcmp(sel, "low"));
+
+ /* selected at position 1 */
+ parse_ok("low [normal] high\n", &c);
+ sel = igt_sysfs_choice_selected(&c);
+ igt_assert(sel);
+ igt_assert(!strcmp(sel, "normal"));
+
+ /* selected at position 2 */
+ parse_ok("low normal [high]\n", &c);
+ sel = igt_sysfs_choice_selected(&c);
+ igt_assert(sel);
+ igt_assert(!strcmp(sel, "high"));
+}
+
+static void test_selected_invalid_index(void)
+{
+ struct igt_sysfs_choice c;
+ const char *sel;
+
+ /* selected = -1 */
+ parse_ok("[only]\n", &c);
+ c.selected = -1;
+ sel = igt_sysfs_choice_selected(&c);
+ igt_assert(!sel);
+
+ /* selected >= num_tokens */
+ parse_ok("[only]\n", &c);
+ c.selected = 999;
+ sel = igt_sysfs_choice_selected(&c);
+ igt_assert(!sel);
+
+ /* empty choice */
+ memset(&c, 0, sizeof(c));
+ sel = igt_sysfs_choice_selected(&c);
+ igt_assert(!sel);
+}
+
+static void test_to_string_roundtrip(void)
+{
+ struct igt_sysfs_choice c1, c2;
+ char out[IGT_SYSFS_CHOICE_MAX_LEN];
+ int ret;
+
+ parse_ok(" low [normal] high \n", &c1);
+
+ ret = igt_sysfs_choice_to_string(&c1, out, sizeof(out));
+ igt_assert_eq(ret, 0);
+
+ /*
+ * Expect canonical format: tokens separated by single spaces,
+ * one [selected], no trailing newline.
+ */
+ igt_assert_f(!strcmp(out, "low [normal] high"),
+ "choice_to_string produced '%s'\n", out);
+
+ /* Parse again and ensure we get the same structure. */
+ parse_ok(out, &c2);
+
+ igt_assert_eq(c2.num_tokens, 3);
+ assert_token(&c2, 0, "low");
+ assert_token(&c2, 1, "normal");
+ assert_token(&c2, 2, "high");
+ igt_assert_eq(c2.selected, 1);
+}
+
+static void test_find_basic(void)
+{
+ struct igt_sysfs_choice c;
+ int idx;
+
+ parse_ok("[low] normal high\n", &c);
+
+ idx = igt_sysfs_choice_find(&c, "low");
+ igt_assert_eq(idx, 0);
+
+ idx = igt_sysfs_choice_find(&c, "normal");
+ igt_assert_eq(idx, 1);
+
+ idx = igt_sysfs_choice_find(&c, "high");
+ igt_assert_eq(idx, 2);
+
+ idx = igt_sysfs_choice_find(&c, "ultra");
+ igt_assert_lt(idx, 0);
+}
+
+static const char *const prio_names[] = {
+ "low",
+ "normal",
+ "high",
+};
+
+static void test_to_mask_basic(void)
+{
+ struct igt_sysfs_choice c;
+ unsigned int mask = 0;
+ int selected_idx = -1;
+ int ret;
+
+ parse_ok("[low] normal high\n", &c);
+
+ ret = igt_sysfs_choice_to_mask(&c, prio_names, ARRAY_SIZE(prio_names),
+ &mask, &selected_idx);
+ igt_assert_eq(ret, 0);
+
+ /* low | normal | high -> bits 0,1,2 set */
+ igt_assert_eq(mask, BIT(0) | BIT(1) | BIT(2));
+ igt_assert_eq(selected_idx, 0);
+}
+
+static void test_to_mask_ignores_unknown(void)
+{
+ struct igt_sysfs_choice c;
+ unsigned int mask = 0;
+ int selected_idx = -1;
+ int ret;
+
+ parse_ok("[low] normal extra\n", &c);
+
+ ret = igt_sysfs_choice_to_mask(&c, prio_names, ARRAY_SIZE(prio_names),
+ &mask, &selected_idx);
+ igt_assert_eq(ret, 0);
+
+ /* "extra" is ignored, only low + normal mapped */
+ igt_assert_eq(mask, BIT(0) | BIT(1));
+ igt_assert_eq(selected_idx, 0);
+}
+
+static void test_to_mask_selected_unknown(void)
+{
+ struct igt_sysfs_choice c;
+ unsigned int mask = 0;
+ int selected_idx = 123;
+ int ret;
+
+ parse_ok("low normal [extra]\n", &c);
+
+ ret = igt_sysfs_choice_to_mask(&c, prio_names, ARRAY_SIZE(prio_names),
+ &mask, &selected_idx);
+ igt_assert_eq(ret, 0);
+
+ igt_assert_eq(mask, BIT(0) | BIT(1)); /* low + normal */
+ igt_assert_eq(selected_idx, -1);
+}
+
+static void test_format_mask_basic(void)
+{
+ char buf[128];
+ int ret;
+
+ /* mask for low + normal + high, selected = normal (1) */
+ ret = igt_sysfs_choice_format_mask(buf, sizeof(buf),
+ prio_names, ARRAY_SIZE(prio_names),
+ BIT(0) | BIT(1) | BIT(2),
+ 1);
+ igt_assert_eq(ret, 0);
+ igt_assert_f(!strcmp(buf, "low [normal] high"),
+ "choice_format_mask produced '%s'\n", buf);
+}
+
+static void test_format_mask_empty(void)
+{
+ char buf[128];
+ int ret;
+
+ ret = igt_sysfs_choice_format_mask(buf, sizeof(buf),
+ prio_names, ARRAY_SIZE(prio_names),
+ 0, -1);
+ igt_assert_eq(ret, 0);
+ igt_assert_eq(buf[0], '\0');
+}
+
+static void test_format_mask_unknown_bit(void)
+{
+ char buf[128];
+ int ret;
+
+ ret = igt_sysfs_choice_format_mask(buf, sizeof(buf),
+ prio_names, ARRAY_SIZE(prio_names),
+ BIT(0) | BIT(3),
+ 0);
+ igt_assert_eq(ret, 0);
+ igt_assert_f(!strcmp(buf, "[low]"),
+ "format_mask produced '%s'\n", buf);
+}
+
+static void test_intersect_basic(void)
+{
+ struct igt_sysfs_choice a, b;
+ int ret;
+
+ parse_ok("[low] normal high\n", &a);
+ parse_ok("low [normal] ultra\n", &b);
+
+ ret = igt_sysfs_choice_intersect(&a, &b);
+ igt_assert_eq(ret, 0);
+
+ igt_assert_eq(a.num_tokens, 2);
+ assert_token(&a, 0, "low");
+ assert_token(&a, 1, "normal");
+
+ /* semantics: selected remains the original selected token if still common */
+ igt_assert_eq(a.selected, 0);
+}
+
+static void test_intersect_single_common(void)
+{
+ struct igt_sysfs_choice a, b;
+ int ret;
+
+ parse_ok("low [normal] high\n", &a);
+ parse_ok("[normal] ultra\n", &b);
+
+ ret = igt_sysfs_choice_intersect(&a, &b);
+ igt_assert_eq(ret, 0);
+
+ igt_assert_eq(a.num_tokens, 1);
+ assert_token(&a, 0, "normal");
+ igt_assert_eq(a.selected, 0);
+}
+
+static void test_intersect_no_common(void)
+{
+ struct igt_sysfs_choice a, b;
+ int ret;
+
+ parse_ok("[low] normal\n", &a);
+ parse_ok("[high] ultra\n", &b);
+
+ ret = igt_sysfs_choice_intersect(&a, &b);
+ igt_assert_eq(ret, -ENOENT);
+}
+
+int igt_simple_main()
+{
+ test_parse_basic_first_selected();
+ test_parse_middle_selected_whitespace();
+ test_parse_single_token();
+ test_parse_error_missing_selected();
+ test_parse_error_multiple_selected();
+ test_parse_error_unterminated_bracket();
+ test_parse_error_too_many_tokens();
+ test_selected_basic();
+ test_selected_invalid_index();
+ test_to_string_roundtrip();
+ test_find_basic();
+ test_to_mask_basic();
+ test_to_mask_ignores_unknown();
+ test_to_mask_selected_unknown();
+ test_format_mask_basic();
+ test_format_mask_empty();
+ test_format_mask_unknown_bit();
+ test_intersect_basic();
+ test_intersect_single_common();
+ test_intersect_no_common();
+}
diff --git a/lib/tests/meson.build b/lib/tests/meson.build
index 1ce19f63c..124a9ecae 100644
--- a/lib/tests/meson.build
+++ b/lib/tests/meson.build
@@ -23,6 +23,7 @@ lib_tests = [
'igt_simulation',
'igt_stats',
'igt_subtest_group',
+ 'igt_sysfs_choice',
'igt_thread',
'igt_types',
'i915_perf_data_alignment',
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* Re: [PATCH v3 i-g-t 02/10] lib/tests/igt_sysfs_choice: Add test coverage
2026-01-28 18:08 ` [PATCH v3 i-g-t 02/10] lib/tests/igt_sysfs_choice: Add test coverage Marcin Bernatowicz
@ 2026-01-29 8:19 ` Laguna, Lukasz
0 siblings, 0 replies; 19+ messages in thread
From: Laguna, Lukasz @ 2026-01-29 8:19 UTC (permalink / raw)
To: Marcin Bernatowicz, igt-dev
Cc: adam.miszczak, jakub1.kolakowski, michal.wajdeczko,
Kamil Konieczny
On 1/28/2026 19:08, Marcin Bernatowicz wrote:
> Add unit tests exercising parsing, selection rules, intersection,
> round-trip formatting, and mask conversion for igt_sysfs_choice.
>
> Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
> Cc: Adam Miszczak <adam.miszczak@linux.intel.com>
> Cc: Jakub Kolakowski <jakub1.kolakowski@intel.com>
> Cc: Kamil Konieczny <kamil.konieczny@linux.intel.com>
> Cc: Lukasz Laguna <lukasz.laguna@intel.com>
Reviewed-by: Lukasz Laguna <lukasz.laguna@intel.com>
> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
>
> ---
> v2:
> - Align igt_simple_main() usage with upstream changes.
> - Corrected date, improved assert messages.
> - Use BIT() instead of (1u << n) for sysfs choice masks.
> - Adjust test for igt_sysfs_choice_to_string() returning error code.
> - Adjust test for igt_sysfs_choice_format_mask() returning error code.
>
> Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
> ---
> lib/tests/igt_sysfs_choice.c | 388 +++++++++++++++++++++++++++++++++++
> lib/tests/meson.build | 1 +
> 2 files changed, 389 insertions(+)
> create mode 100644 lib/tests/igt_sysfs_choice.c
>
> diff --git a/lib/tests/igt_sysfs_choice.c b/lib/tests/igt_sysfs_choice.c
> new file mode 100644
> index 000000000..c573a0dff
> --- /dev/null
> +++ b/lib/tests/igt_sysfs_choice.c
> @@ -0,0 +1,388 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2026 Intel Corporation
> + */
> +#include <errno.h>
> +#include "drmtest.h"
> +#include "igt_core.h"
> +#include "intel_chipset.h"
> +#include "igt_sysfs_choice.h"
> +
> +static void assert_token(const struct igt_sysfs_choice *c,
> + size_t idx, const char *expected)
> +{
> + igt_assert_f(idx < c->num_tokens,
> + "token index %zu out of range (num_tokens=%zu)\n",
> + idx, c->num_tokens);
> + igt_assert(c->tokens[idx]);
> + igt_assert_f(!strcmp(c->tokens[idx], expected),
> + "token[%zu] mismatch: got='%s' expected='%s'\n",
> + idx, c->tokens[idx], expected);
> +}
> +
> +static void parse_ok(const char *str, struct igt_sysfs_choice *choice)
> +{
> + int ret;
> +
> + ret = igt_sysfs_choice_parse(str, choice);
> + igt_assert_f(ret == 0, "parse(\"%s\") failed: %d\n", str, ret);
> +}
> +
> +static void test_parse_basic_first_selected(void)
> +{
> + struct igt_sysfs_choice c;
> +
> + parse_ok("[low] normal high\n", &c);
> +
> + igt_assert_eq(c.num_tokens, 3);
> + assert_token(&c, 0, "low");
> + assert_token(&c, 1, "normal");
> + assert_token(&c, 2, "high");
> +
> + igt_assert_eq(c.selected, 0);
> +}
> +
> +static void test_parse_middle_selected_whitespace(void)
> +{
> + struct igt_sysfs_choice c;
> +
> + parse_ok(" low [normal] high \n", &c);
> +
> + igt_assert_eq(c.num_tokens, 3);
> + assert_token(&c, 0, "low");
> + assert_token(&c, 1, "normal");
> + assert_token(&c, 2, "high");
> +
> + igt_assert_eq(c.selected, 1);
> +}
> +
> +static void test_parse_single_token(void)
> +{
> + struct igt_sysfs_choice c;
> +
> + parse_ok("[only]\n", &c);
> +
> + igt_assert_eq(c.num_tokens, 1);
> + assert_token(&c, 0, "only");
> + igt_assert_eq(c.selected, 0);
> +}
> +
> +static void test_parse_error_missing_selected(void)
> +{
> + struct igt_sysfs_choice c;
> + int ret;
> +
> + ret = igt_sysfs_choice_parse("low normal high\n", &c);
> + igt_assert_eq(ret, -EINVAL);
> +}
> +
> +static void test_parse_error_multiple_selected(void)
> +{
> + struct igt_sysfs_choice c;
> + int ret;
> +
> + ret = igt_sysfs_choice_parse("[low] [normal] high\n", &c);
> + igt_assert_eq(ret, -EINVAL);
> +
> + ret = igt_sysfs_choice_parse("low [normal] [high]\n", &c);
> + igt_assert_eq(ret, -EINVAL);
> +}
> +
> +static void test_parse_error_unterminated_bracket(void)
> +{
> + struct igt_sysfs_choice c;
> + int ret;
> +
> + ret = igt_sysfs_choice_parse("[low normal high\n", &c);
> + igt_assert_eq(ret, -EINVAL);
> +
> + ret = igt_sysfs_choice_parse("low [normal high]\n", &c);
> + igt_assert_eq(ret, -EINVAL);
> +}
> +
> +static void test_parse_error_too_many_tokens(void)
> +{
> + struct igt_sysfs_choice c;
> + char buf[512];
> + size_t i;
> + int len = 0;
> + int ret;
> +
> + /*
> + * Build a line with (IGT_SYSFS_CHOICE_MAX_TOKENS + 1) tokens:
> + * "[t0] t1 t2 ... tN"
> + */
> + len += snprintf(buf + len, sizeof(buf) - len, "[t0]");
> + for (i = 1; i < IGT_SYSFS_CHOICE_MAX_TOKENS + 1 && len < (int)sizeof(buf); i++)
> + len += snprintf(buf + len, sizeof(buf) - len, " t%zu", i);
> + len += snprintf(buf + len, sizeof(buf) - len, "\n");
> +
> + ret = igt_sysfs_choice_parse(buf, &c);
> + igt_assert_eq(ret, -E2BIG);
> +}
> +
> +static void test_selected_basic(void)
> +{
> + struct igt_sysfs_choice c;
> + const char *sel;
> +
> + /* selected at position 0 */
> + parse_ok("[low] normal high\n", &c);
> + sel = igt_sysfs_choice_selected(&c);
> + igt_assert(sel);
> + igt_assert(!strcmp(sel, "low"));
> +
> + /* selected at position 1 */
> + parse_ok("low [normal] high\n", &c);
> + sel = igt_sysfs_choice_selected(&c);
> + igt_assert(sel);
> + igt_assert(!strcmp(sel, "normal"));
> +
> + /* selected at position 2 */
> + parse_ok("low normal [high]\n", &c);
> + sel = igt_sysfs_choice_selected(&c);
> + igt_assert(sel);
> + igt_assert(!strcmp(sel, "high"));
> +}
> +
> +static void test_selected_invalid_index(void)
> +{
> + struct igt_sysfs_choice c;
> + const char *sel;
> +
> + /* selected = -1 */
> + parse_ok("[only]\n", &c);
> + c.selected = -1;
> + sel = igt_sysfs_choice_selected(&c);
> + igt_assert(!sel);
> +
> + /* selected >= num_tokens */
> + parse_ok("[only]\n", &c);
> + c.selected = 999;
> + sel = igt_sysfs_choice_selected(&c);
> + igt_assert(!sel);
> +
> + /* empty choice */
> + memset(&c, 0, sizeof(c));
> + sel = igt_sysfs_choice_selected(&c);
> + igt_assert(!sel);
> +}
> +
> +static void test_to_string_roundtrip(void)
> +{
> + struct igt_sysfs_choice c1, c2;
> + char out[IGT_SYSFS_CHOICE_MAX_LEN];
> + int ret;
> +
> + parse_ok(" low [normal] high \n", &c1);
> +
> + ret = igt_sysfs_choice_to_string(&c1, out, sizeof(out));
> + igt_assert_eq(ret, 0);
> +
> + /*
> + * Expect canonical format: tokens separated by single spaces,
> + * one [selected], no trailing newline.
> + */
> + igt_assert_f(!strcmp(out, "low [normal] high"),
> + "choice_to_string produced '%s'\n", out);
> +
> + /* Parse again and ensure we get the same structure. */
> + parse_ok(out, &c2);
> +
> + igt_assert_eq(c2.num_tokens, 3);
> + assert_token(&c2, 0, "low");
> + assert_token(&c2, 1, "normal");
> + assert_token(&c2, 2, "high");
> + igt_assert_eq(c2.selected, 1);
> +}
> +
> +static void test_find_basic(void)
> +{
> + struct igt_sysfs_choice c;
> + int idx;
> +
> + parse_ok("[low] normal high\n", &c);
> +
> + idx = igt_sysfs_choice_find(&c, "low");
> + igt_assert_eq(idx, 0);
> +
> + idx = igt_sysfs_choice_find(&c, "normal");
> + igt_assert_eq(idx, 1);
> +
> + idx = igt_sysfs_choice_find(&c, "high");
> + igt_assert_eq(idx, 2);
> +
> + idx = igt_sysfs_choice_find(&c, "ultra");
> + igt_assert_lt(idx, 0);
> +}
> +
> +static const char *const prio_names[] = {
> + "low",
> + "normal",
> + "high",
> +};
> +
> +static void test_to_mask_basic(void)
> +{
> + struct igt_sysfs_choice c;
> + unsigned int mask = 0;
> + int selected_idx = -1;
> + int ret;
> +
> + parse_ok("[low] normal high\n", &c);
> +
> + ret = igt_sysfs_choice_to_mask(&c, prio_names, ARRAY_SIZE(prio_names),
> + &mask, &selected_idx);
> + igt_assert_eq(ret, 0);
> +
> + /* low | normal | high -> bits 0,1,2 set */
> + igt_assert_eq(mask, BIT(0) | BIT(1) | BIT(2));
> + igt_assert_eq(selected_idx, 0);
> +}
> +
> +static void test_to_mask_ignores_unknown(void)
> +{
> + struct igt_sysfs_choice c;
> + unsigned int mask = 0;
> + int selected_idx = -1;
> + int ret;
> +
> + parse_ok("[low] normal extra\n", &c);
> +
> + ret = igt_sysfs_choice_to_mask(&c, prio_names, ARRAY_SIZE(prio_names),
> + &mask, &selected_idx);
> + igt_assert_eq(ret, 0);
> +
> + /* "extra" is ignored, only low + normal mapped */
> + igt_assert_eq(mask, BIT(0) | BIT(1));
> + igt_assert_eq(selected_idx, 0);
> +}
> +
> +static void test_to_mask_selected_unknown(void)
> +{
> + struct igt_sysfs_choice c;
> + unsigned int mask = 0;
> + int selected_idx = 123;
> + int ret;
> +
> + parse_ok("low normal [extra]\n", &c);
> +
> + ret = igt_sysfs_choice_to_mask(&c, prio_names, ARRAY_SIZE(prio_names),
> + &mask, &selected_idx);
> + igt_assert_eq(ret, 0);
> +
> + igt_assert_eq(mask, BIT(0) | BIT(1)); /* low + normal */
> + igt_assert_eq(selected_idx, -1);
> +}
> +
> +static void test_format_mask_basic(void)
> +{
> + char buf[128];
> + int ret;
> +
> + /* mask for low + normal + high, selected = normal (1) */
> + ret = igt_sysfs_choice_format_mask(buf, sizeof(buf),
> + prio_names, ARRAY_SIZE(prio_names),
> + BIT(0) | BIT(1) | BIT(2),
> + 1);
> + igt_assert_eq(ret, 0);
> + igt_assert_f(!strcmp(buf, "low [normal] high"),
> + "choice_format_mask produced '%s'\n", buf);
> +}
> +
> +static void test_format_mask_empty(void)
> +{
> + char buf[128];
> + int ret;
> +
> + ret = igt_sysfs_choice_format_mask(buf, sizeof(buf),
> + prio_names, ARRAY_SIZE(prio_names),
> + 0, -1);
> + igt_assert_eq(ret, 0);
> + igt_assert_eq(buf[0], '\0');
> +}
> +
> +static void test_format_mask_unknown_bit(void)
> +{
> + char buf[128];
> + int ret;
> +
> + ret = igt_sysfs_choice_format_mask(buf, sizeof(buf),
> + prio_names, ARRAY_SIZE(prio_names),
> + BIT(0) | BIT(3),
> + 0);
> + igt_assert_eq(ret, 0);
> + igt_assert_f(!strcmp(buf, "[low]"),
> + "format_mask produced '%s'\n", buf);
> +}
> +
> +static void test_intersect_basic(void)
> +{
> + struct igt_sysfs_choice a, b;
> + int ret;
> +
> + parse_ok("[low] normal high\n", &a);
> + parse_ok("low [normal] ultra\n", &b);
> +
> + ret = igt_sysfs_choice_intersect(&a, &b);
> + igt_assert_eq(ret, 0);
> +
> + igt_assert_eq(a.num_tokens, 2);
> + assert_token(&a, 0, "low");
> + assert_token(&a, 1, "normal");
> +
> + /* semantics: selected remains the original selected token if still common */
> + igt_assert_eq(a.selected, 0);
> +}
> +
> +static void test_intersect_single_common(void)
> +{
> + struct igt_sysfs_choice a, b;
> + int ret;
> +
> + parse_ok("low [normal] high\n", &a);
> + parse_ok("[normal] ultra\n", &b);
> +
> + ret = igt_sysfs_choice_intersect(&a, &b);
> + igt_assert_eq(ret, 0);
> +
> + igt_assert_eq(a.num_tokens, 1);
> + assert_token(&a, 0, "normal");
> + igt_assert_eq(a.selected, 0);
> +}
> +
> +static void test_intersect_no_common(void)
> +{
> + struct igt_sysfs_choice a, b;
> + int ret;
> +
> + parse_ok("[low] normal\n", &a);
> + parse_ok("[high] ultra\n", &b);
> +
> + ret = igt_sysfs_choice_intersect(&a, &b);
> + igt_assert_eq(ret, -ENOENT);
> +}
> +
> +int igt_simple_main()
> +{
> + test_parse_basic_first_selected();
> + test_parse_middle_selected_whitespace();
> + test_parse_single_token();
> + test_parse_error_missing_selected();
> + test_parse_error_multiple_selected();
> + test_parse_error_unterminated_bracket();
> + test_parse_error_too_many_tokens();
> + test_selected_basic();
> + test_selected_invalid_index();
> + test_to_string_roundtrip();
> + test_find_basic();
> + test_to_mask_basic();
> + test_to_mask_ignores_unknown();
> + test_to_mask_selected_unknown();
> + test_format_mask_basic();
> + test_format_mask_empty();
> + test_format_mask_unknown_bit();
> + test_intersect_basic();
> + test_intersect_single_common();
> + test_intersect_no_common();
> +}
> diff --git a/lib/tests/meson.build b/lib/tests/meson.build
> index 1ce19f63c..124a9ecae 100644
> --- a/lib/tests/meson.build
> +++ b/lib/tests/meson.build
> @@ -23,6 +23,7 @@ lib_tests = [
> 'igt_simulation',
> 'igt_stats',
> 'igt_subtest_group',
> + 'igt_sysfs_choice',
> 'igt_thread',
> 'igt_types',
> 'i915_perf_data_alignment',
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 i-g-t 03/10] lib/xe/xe_sriov_provisioning: Add string conversion helpers for scheduling priority
2026-01-28 18:08 [PATCH v3 i-g-t 00/10] Xe SR-IOV admin scheduling helpers and test updates Marcin Bernatowicz
2026-01-28 18:08 ` [PATCH v3 i-g-t 01/10] lib/igt_sysfs_choice: Add helpers for sysfs enumerated choice attributes Marcin Bernatowicz
2026-01-28 18:08 ` [PATCH v3 i-g-t 02/10] lib/tests/igt_sysfs_choice: Add test coverage Marcin Bernatowicz
@ 2026-01-28 18:08 ` Marcin Bernatowicz
2026-01-28 18:08 ` [PATCH v3 i-g-t 04/10] lib/xe/xe_sriov_provisioning: Add sched priority mask to string helper Marcin Bernatowicz
` (8 subsequent siblings)
11 siblings, 0 replies; 19+ messages in thread
From: Marcin Bernatowicz @ 2026-01-28 18:08 UTC (permalink / raw)
To: igt-dev
Cc: adam.miszczak, jakub1.kolakowski, lukasz.laguna, michal.wajdeczko,
Marcin Bernatowicz
Introduce helper functions to convert between xe_sriov_sched_priority
enum values and their string representations.
Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
Reviewed-by: Lukasz Laguna <lukasz.laguna@intel.com>
Cc: Adam Miszczak <adam.miszczak@linux.intel.com>
Cc: Jakub Kolakowski <jakub1.kolakowski@intel.com>
Cc: Lukasz Laguna <lukasz.laguna@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
---
lib/xe/xe_sriov_provisioning.c | 58 ++++++++++++++++++++++++++++++++++
lib/xe/xe_sriov_provisioning.h | 2 ++
2 files changed, 60 insertions(+)
diff --git a/lib/xe/xe_sriov_provisioning.c b/lib/xe/xe_sriov_provisioning.c
index 116cd3255..c2a1db4bc 100644
--- a/lib/xe/xe_sriov_provisioning.c
+++ b/lib/xe/xe_sriov_provisioning.c
@@ -5,6 +5,7 @@
#include <errno.h>
+#include "drmtest.h"
#include "igt_core.h"
#include "igt_debugfs.h"
#include "igt_sriov_device.h"
@@ -599,6 +600,63 @@ void xe_sriov_set_sched_if_idle(int pf, unsigned int gt_num, bool value)
igt_fail_on(__xe_sriov_set_sched_if_idle(pf, gt_num, value));
}
+static const char * const xe_sriov_sched_priority_str[] = {
+ [XE_SRIOV_SCHED_PRIORITY_LOW] = "low",
+ [XE_SRIOV_SCHED_PRIORITY_NORMAL] = "normal",
+ [XE_SRIOV_SCHED_PRIORITY_HIGH] = "high",
+};
+
+_Static_assert(ARRAY_SIZE(xe_sriov_sched_priority_str) == (XE_SRIOV_SCHED_PRIORITY_HIGH + 1),
+ "sched priority table must cover 0..HIGH");
+
+/**
+ * xe_sriov_sched_priority_to_string - Convert scheduling priority enum to string
+ * @prio: SR-IOV scheduling priority value
+ *
+ * Converts an enumeration value of type &enum xe_sriov_sched_priority
+ * into its corresponding string representation.
+ *
+ * Return: A pointer to a constant string literal ("low", "normal", or "high"),
+ * or %NULL if the value is invalid or unrecognized.
+ */
+const char *xe_sriov_sched_priority_to_string(enum xe_sriov_sched_priority prio)
+{
+ switch (prio) {
+ case XE_SRIOV_SCHED_PRIORITY_LOW:
+ case XE_SRIOV_SCHED_PRIORITY_NORMAL:
+ case XE_SRIOV_SCHED_PRIORITY_HIGH:
+ return xe_sriov_sched_priority_str[prio];
+ }
+
+ return NULL;
+}
+
+/**
+ * xe_sriov_sched_priority_from_string - Parse scheduling priority from string
+ * @s: NUL-terminated string to parse
+ * @prio: Output pointer to store parsed enum value
+ *
+ * Parses a string representing a scheduling priority ("low", "normal", "high")
+ * into the corresponding &enum xe_sriov_sched_priority value.
+ *
+ * Return: 0 on success, -EINVAL if the string is invalid or unrecognized.
+ */
+int xe_sriov_sched_priority_from_string(const char *s,
+ enum xe_sriov_sched_priority *prio)
+{
+ igt_assert(s && prio);
+
+ for (size_t i = 0; i < ARRAY_SIZE(xe_sriov_sched_priority_str); i++) {
+ const char *name = xe_sriov_sched_priority_str[i];
+
+ if (name && !strcmp(s, name)) {
+ *prio = (enum xe_sriov_sched_priority)i;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
/**
* __xe_sriov_get_sched_priority - Get the scheduling priority for a given VF
* @pf: PF device file descriptor
diff --git a/lib/xe/xe_sriov_provisioning.h b/lib/xe/xe_sriov_provisioning.h
index ab5347fd6..c9b321d58 100644
--- a/lib/xe/xe_sriov_provisioning.h
+++ b/lib/xe/xe_sriov_provisioning.h
@@ -136,6 +136,8 @@ int __xe_sriov_set_engine_reset(int pf, unsigned int gt_num, bool value);
void xe_sriov_set_engine_reset(int pf, unsigned int gt_num, bool value);
int __xe_sriov_set_sched_if_idle(int pf, unsigned int gt_num, bool value);
void xe_sriov_set_sched_if_idle(int pf, unsigned int gt_num, bool value);
+const char *xe_sriov_sched_priority_to_string(enum xe_sriov_sched_priority value);
+int xe_sriov_sched_priority_from_string(const char *s, enum xe_sriov_sched_priority *value);
int __xe_sriov_get_sched_priority(int pf, unsigned int vf_num,
unsigned int gt_num,
enum xe_sriov_sched_priority *value);
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH v3 i-g-t 04/10] lib/xe/xe_sriov_provisioning: Add sched priority mask to string helper
2026-01-28 18:08 [PATCH v3 i-g-t 00/10] Xe SR-IOV admin scheduling helpers and test updates Marcin Bernatowicz
` (2 preceding siblings ...)
2026-01-28 18:08 ` [PATCH v3 i-g-t 03/10] lib/xe/xe_sriov_provisioning: Add string conversion helpers for scheduling priority Marcin Bernatowicz
@ 2026-01-28 18:08 ` Marcin Bernatowicz
2026-01-29 8:19 ` Laguna, Lukasz
2026-01-28 18:08 ` [PATCH v3 i-g-t 05/10] lib/igt_sriov_device: Add helper for PF/VF sysfs path formatting Marcin Bernatowicz
` (7 subsequent siblings)
11 siblings, 1 reply; 19+ messages in thread
From: Marcin Bernatowicz @ 2026-01-28 18:08 UTC (permalink / raw)
To: igt-dev
Cc: adam.miszczak, jakub1.kolakowski, lukasz.laguna, michal.wajdeczko,
Marcin Bernatowicz
Introduce xe_sriov_sched_priority_mask_to_string() to format a
scheduling priority bitmask as a space-separated list of priority names.
Introduce xe_sriov_sched_priority_choice_to_mask() to convert an
igt_sysfs_choice into a bitmask and a selected priority index.
Both helpers are thin wrappers around the generic igt_sysfs_choice
functions.
Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
Cc: Adam Miszczak <adam.miszczak@linux.intel.com>
Cc: Jakub Kolakowski <jakub1.kolakowski@intel.com>
Cc: Lukasz Laguna <lukasz.laguna@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
---
v2:
- Make xe_sriov_sched_priority_mask_to_string() return error code
instead of NULL.
- Add doc for xe_sriov_sched_priority_mask_to_string() and define it first
Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
---
lib/xe/xe_sriov_provisioning.c | 47 ++++++++++++++++++++++++++++++++++
lib/xe/xe_sriov_provisioning.h | 13 ++++++++++
2 files changed, 60 insertions(+)
diff --git a/lib/xe/xe_sriov_provisioning.c b/lib/xe/xe_sriov_provisioning.c
index c2a1db4bc..f8dda09fb 100644
--- a/lib/xe/xe_sriov_provisioning.c
+++ b/lib/xe/xe_sriov_provisioning.c
@@ -9,6 +9,8 @@
#include "igt_core.h"
#include "igt_debugfs.h"
#include "igt_sriov_device.h"
+#include "igt_sysfs.h"
+#include "igt_sysfs_choice.h"
#include "intel_chipset.h"
#include "linux_scaffold.h"
#include "xe/xe_query.h"
@@ -657,6 +659,51 @@ int xe_sriov_sched_priority_from_string(const char *s,
return -EINVAL;
}
+/**
+ * xe_sriov_sched_priority_choice_to_mask - Map parsed sysfs choice to mask + selection
+ * @choice: Parsed choice (tokens + selected index)
+ * @mask: Output bitmask of known priorities present in @choice
+ * @selected_idx: Output selected priority index in the known-name table, or -1
+ *
+ * Converts an &struct igt_sysfs_choice representing the sched_priority sysfs
+ * attribute into a bitmask and an optional selected index.
+ *
+ * The bit positions in @mask correspond to &enum xe_sriov_sched_priority values
+ * (LOW/NORMAL/HIGH). Unknown tokens in @choice are ignored (best-effort), so
+ * tests can tolerate kernels that add extra choices.
+ *
+ * Return: 0 on success, -EINVAL on invalid arguments.
+ */
+int xe_sriov_sched_priority_choice_to_mask(const struct igt_sysfs_choice *choice,
+ unsigned int *mask, int *selected_idx)
+{
+ return igt_sysfs_choice_to_mask(choice, xe_sriov_sched_priority_str,
+ ARRAY_SIZE(xe_sriov_sched_priority_str),
+ mask, selected_idx);
+}
+
+/**
+ * xe_sriov_sched_priority_mask_to_string - Format priority mask as text
+ * @buf: Output buffer.
+ * @buf_sz: Size of @buf.
+ * @mask: Priority bitmask.
+ * @selected_idx: Index to highlight with brackets, or <0 for none.
+ *
+ * Converts @mask to a space-separated string of priority names. If @selected_idx
+ * is >= 0 and present in @mask, that priority is wrapped in brackets, e.g.
+ * "low [normal] high". An empty @mask results in an empty string.
+ *
+ * Return: 0 on success, -EINVAL on invalid args, -E2BIG if @buf_sz is too small.
+ */
+int xe_sriov_sched_priority_mask_to_string(char *buf, size_t buf_sz,
+ unsigned int mask, int selected_idx)
+{
+ return igt_sysfs_choice_format_mask(buf, buf_sz,
+ xe_sriov_sched_priority_str,
+ ARRAY_SIZE(xe_sriov_sched_priority_str),
+ mask, selected_idx);
+}
+
/**
* __xe_sriov_get_sched_priority - Get the scheduling priority for a given VF
* @pf: PF device file descriptor
diff --git a/lib/xe/xe_sriov_provisioning.h b/lib/xe/xe_sriov_provisioning.h
index c9b321d58..6661b33cc 100644
--- a/lib/xe/xe_sriov_provisioning.h
+++ b/lib/xe/xe_sriov_provisioning.h
@@ -9,6 +9,7 @@
#include <stdint.h>
struct xe_mmio;
+struct igt_sysfs_choice;
/**
* enum xe_sriov_shared_res - Shared resource types
@@ -75,6 +76,14 @@ enum xe_sriov_sched_priority {
XE_SRIOV_SCHED_PRIORITY_HIGH
};
+#define XE_SRIOV_SCHED_PRIORITY_MASK_LOW BIT(XE_SRIOV_SCHED_PRIORITY_LOW)
+#define XE_SRIOV_SCHED_PRIORITY_MASK_NORMAL BIT(XE_SRIOV_SCHED_PRIORITY_NORMAL)
+#define XE_SRIOV_SCHED_PRIORITY_MASK_HIGH BIT(XE_SRIOV_SCHED_PRIORITY_HIGH)
+#define XE_SRIOV_SCHED_PRIORITY_MASK_ALL \
+ (XE_SRIOV_SCHED_PRIORITY_MASK_LOW | \
+ XE_SRIOV_SCHED_PRIORITY_MASK_NORMAL | \
+ XE_SRIOV_SCHED_PRIORITY_MASK_HIGH)
+
/**
* struct xe_sriov_provisioned_range - Provisioned range for a Virtual Function (VF)
* @vf_id: The ID of the VF
@@ -138,6 +147,10 @@ int __xe_sriov_set_sched_if_idle(int pf, unsigned int gt_num, bool value);
void xe_sriov_set_sched_if_idle(int pf, unsigned int gt_num, bool value);
const char *xe_sriov_sched_priority_to_string(enum xe_sriov_sched_priority value);
int xe_sriov_sched_priority_from_string(const char *s, enum xe_sriov_sched_priority *value);
+int xe_sriov_sched_priority_choice_to_mask(const struct igt_sysfs_choice *choice,
+ unsigned int *mask, int *selected_idx);
+int xe_sriov_sched_priority_mask_to_string(char *buf, size_t buf_sz,
+ unsigned int mask, int selected_idx);
int __xe_sriov_get_sched_priority(int pf, unsigned int vf_num,
unsigned int gt_num,
enum xe_sriov_sched_priority *value);
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* Re: [PATCH v3 i-g-t 04/10] lib/xe/xe_sriov_provisioning: Add sched priority mask to string helper
2026-01-28 18:08 ` [PATCH v3 i-g-t 04/10] lib/xe/xe_sriov_provisioning: Add sched priority mask to string helper Marcin Bernatowicz
@ 2026-01-29 8:19 ` Laguna, Lukasz
0 siblings, 0 replies; 19+ messages in thread
From: Laguna, Lukasz @ 2026-01-29 8:19 UTC (permalink / raw)
To: Marcin Bernatowicz, igt-dev
Cc: adam.miszczak, jakub1.kolakowski, michal.wajdeczko
On 1/28/2026 19:08, Marcin Bernatowicz wrote:
> Introduce xe_sriov_sched_priority_mask_to_string() to format a
> scheduling priority bitmask as a space-separated list of priority names.
> Introduce xe_sriov_sched_priority_choice_to_mask() to convert an
> igt_sysfs_choice into a bitmask and a selected priority index.
>
> Both helpers are thin wrappers around the generic igt_sysfs_choice
> functions.
>
> Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
> Cc: Adam Miszczak <adam.miszczak@linux.intel.com>
> Cc: Jakub Kolakowski <jakub1.kolakowski@intel.com>
> Cc: Lukasz Laguna <lukasz.laguna@intel.com>
Reviewed-by: Lukasz Laguna <lukasz.laguna@intel.com>
> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
>
> ---
> v2:
> - Make xe_sriov_sched_priority_mask_to_string() return error code
> instead of NULL.
> - Add doc for xe_sriov_sched_priority_mask_to_string() and define it first
>
> Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
> ---
> lib/xe/xe_sriov_provisioning.c | 47 ++++++++++++++++++++++++++++++++++
> lib/xe/xe_sriov_provisioning.h | 13 ++++++++++
> 2 files changed, 60 insertions(+)
>
> diff --git a/lib/xe/xe_sriov_provisioning.c b/lib/xe/xe_sriov_provisioning.c
> index c2a1db4bc..f8dda09fb 100644
> --- a/lib/xe/xe_sriov_provisioning.c
> +++ b/lib/xe/xe_sriov_provisioning.c
> @@ -9,6 +9,8 @@
> #include "igt_core.h"
> #include "igt_debugfs.h"
> #include "igt_sriov_device.h"
> +#include "igt_sysfs.h"
> +#include "igt_sysfs_choice.h"
> #include "intel_chipset.h"
> #include "linux_scaffold.h"
> #include "xe/xe_query.h"
> @@ -657,6 +659,51 @@ int xe_sriov_sched_priority_from_string(const char *s,
> return -EINVAL;
> }
>
> +/**
> + * xe_sriov_sched_priority_choice_to_mask - Map parsed sysfs choice to mask + selection
> + * @choice: Parsed choice (tokens + selected index)
> + * @mask: Output bitmask of known priorities present in @choice
> + * @selected_idx: Output selected priority index in the known-name table, or -1
> + *
> + * Converts an &struct igt_sysfs_choice representing the sched_priority sysfs
> + * attribute into a bitmask and an optional selected index.
> + *
> + * The bit positions in @mask correspond to &enum xe_sriov_sched_priority values
> + * (LOW/NORMAL/HIGH). Unknown tokens in @choice are ignored (best-effort), so
> + * tests can tolerate kernels that add extra choices.
> + *
> + * Return: 0 on success, -EINVAL on invalid arguments.
> + */
> +int xe_sriov_sched_priority_choice_to_mask(const struct igt_sysfs_choice *choice,
> + unsigned int *mask, int *selected_idx)
> +{
> + return igt_sysfs_choice_to_mask(choice, xe_sriov_sched_priority_str,
> + ARRAY_SIZE(xe_sriov_sched_priority_str),
> + mask, selected_idx);
> +}
> +
> +/**
> + * xe_sriov_sched_priority_mask_to_string - Format priority mask as text
> + * @buf: Output buffer.
> + * @buf_sz: Size of @buf.
> + * @mask: Priority bitmask.
> + * @selected_idx: Index to highlight with brackets, or <0 for none.
> + *
> + * Converts @mask to a space-separated string of priority names. If @selected_idx
> + * is >= 0 and present in @mask, that priority is wrapped in brackets, e.g.
> + * "low [normal] high". An empty @mask results in an empty string.
> + *
> + * Return: 0 on success, -EINVAL on invalid args, -E2BIG if @buf_sz is too small.
> + */
> +int xe_sriov_sched_priority_mask_to_string(char *buf, size_t buf_sz,
> + unsigned int mask, int selected_idx)
> +{
> + return igt_sysfs_choice_format_mask(buf, buf_sz,
> + xe_sriov_sched_priority_str,
> + ARRAY_SIZE(xe_sriov_sched_priority_str),
> + mask, selected_idx);
> +}
> +
> /**
> * __xe_sriov_get_sched_priority - Get the scheduling priority for a given VF
> * @pf: PF device file descriptor
> diff --git a/lib/xe/xe_sriov_provisioning.h b/lib/xe/xe_sriov_provisioning.h
> index c9b321d58..6661b33cc 100644
> --- a/lib/xe/xe_sriov_provisioning.h
> +++ b/lib/xe/xe_sriov_provisioning.h
> @@ -9,6 +9,7 @@
> #include <stdint.h>
>
> struct xe_mmio;
> +struct igt_sysfs_choice;
>
> /**
> * enum xe_sriov_shared_res - Shared resource types
> @@ -75,6 +76,14 @@ enum xe_sriov_sched_priority {
> XE_SRIOV_SCHED_PRIORITY_HIGH
> };
>
> +#define XE_SRIOV_SCHED_PRIORITY_MASK_LOW BIT(XE_SRIOV_SCHED_PRIORITY_LOW)
> +#define XE_SRIOV_SCHED_PRIORITY_MASK_NORMAL BIT(XE_SRIOV_SCHED_PRIORITY_NORMAL)
> +#define XE_SRIOV_SCHED_PRIORITY_MASK_HIGH BIT(XE_SRIOV_SCHED_PRIORITY_HIGH)
> +#define XE_SRIOV_SCHED_PRIORITY_MASK_ALL \
> + (XE_SRIOV_SCHED_PRIORITY_MASK_LOW | \
> + XE_SRIOV_SCHED_PRIORITY_MASK_NORMAL | \
> + XE_SRIOV_SCHED_PRIORITY_MASK_HIGH)
> +
> /**
> * struct xe_sriov_provisioned_range - Provisioned range for a Virtual Function (VF)
> * @vf_id: The ID of the VF
> @@ -138,6 +147,10 @@ int __xe_sriov_set_sched_if_idle(int pf, unsigned int gt_num, bool value);
> void xe_sriov_set_sched_if_idle(int pf, unsigned int gt_num, bool value);
> const char *xe_sriov_sched_priority_to_string(enum xe_sriov_sched_priority value);
> int xe_sriov_sched_priority_from_string(const char *s, enum xe_sriov_sched_priority *value);
> +int xe_sriov_sched_priority_choice_to_mask(const struct igt_sysfs_choice *choice,
> + unsigned int *mask, int *selected_idx);
> +int xe_sriov_sched_priority_mask_to_string(char *buf, size_t buf_sz,
> + unsigned int mask, int selected_idx);
> int __xe_sriov_get_sched_priority(int pf, unsigned int vf_num,
> unsigned int gt_num,
> enum xe_sriov_sched_priority *value);
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 i-g-t 05/10] lib/igt_sriov_device: Add helper for PF/VF sysfs path formatting
2026-01-28 18:08 [PATCH v3 i-g-t 00/10] Xe SR-IOV admin scheduling helpers and test updates Marcin Bernatowicz
` (3 preceding siblings ...)
2026-01-28 18:08 ` [PATCH v3 i-g-t 04/10] lib/xe/xe_sriov_provisioning: Add sched priority mask to string helper Marcin Bernatowicz
@ 2026-01-28 18:08 ` Marcin Bernatowicz
2026-01-28 18:08 ` [PATCH v3 i-g-t 06/10] lib/xe/xe_sriov_admin: Add SR-IOV admin sysfs accessors Marcin Bernatowicz
` (6 subsequent siblings)
11 siblings, 0 replies; 19+ messages in thread
From: Marcin Bernatowicz @ 2026-01-28 18:08 UTC (permalink / raw)
To: igt-dev
Cc: adam.miszczak, jakub1.kolakowski, lukasz.laguna, michal.wajdeczko,
Marcin Bernatowicz
Add igt_sriov_func_str() — a small utility that returns "pf" for
function 0 and "vf%u" for any VF index. This helper allows callers
to build SR-IOV sysfs paths without duplicating PF/VF conditional
logic.
Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
Reviewed-by: Lukasz Laguna <lukasz.laguna@intel.com>
Cc: Adam Miszczak <adam.miszczak@linux.intel.com>
Cc: Jakub Kolakowski <jakub1.kolakowski@intel.com>
Cc: Lukasz Laguna <lukasz.laguna@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
---
lib/igt_sriov_device.c | 19 +++++++++++++++++++
lib/igt_sriov_device.h | 1 +
2 files changed, 20 insertions(+)
diff --git a/lib/igt_sriov_device.c b/lib/igt_sriov_device.c
index ffa996d6b..788ffbfa1 100644
--- a/lib/igt_sriov_device.c
+++ b/lib/igt_sriov_device.c
@@ -42,6 +42,25 @@ bool igt_sriov_is_pf(int device)
return value > 0;
}
+/**
+ * igt_sriov_func_str - Return "pf" or "vf%u" label for a function number
+ * @vf_num: 0 for PF, >0 for VF index
+ *
+ * Helper for constructing SR-IOV sysfs paths.
+ *
+ * Returns: "pf" for @vf_num == 0, otherwise "vf%u".
+ */
+const char *igt_sriov_func_str(unsigned int vf_num)
+{
+ static __thread char buf[16];
+
+ if (vf_num == 0)
+ return "pf";
+
+ snprintf(buf, sizeof(buf), "vf%u", vf_num);
+ return buf;
+}
+
static bool __pf_attr_get_u32(int pf, const char *attr, uint32_t *value)
{
int sysfs;
diff --git a/lib/igt_sriov_device.h b/lib/igt_sriov_device.h
index 930e97982..84d29b1bb 100644
--- a/lib/igt_sriov_device.h
+++ b/lib/igt_sriov_device.h
@@ -34,6 +34,7 @@ int igt_sriov_device_sysfs_open(int pf, unsigned int vf_num);
bool igt_sriov_device_reset_exists(int pf, unsigned int vf_num);
bool igt_sriov_device_reset(int pf, unsigned int vf_num);
bool intel_is_vf_device(int device);
+const char *igt_sriov_func_str(unsigned int vf_num);
/**
* __is_valid_range - Helper to check VF range is valid
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH v3 i-g-t 06/10] lib/xe/xe_sriov_admin: Add SR-IOV admin sysfs accessors
2026-01-28 18:08 [PATCH v3 i-g-t 00/10] Xe SR-IOV admin scheduling helpers and test updates Marcin Bernatowicz
` (4 preceding siblings ...)
2026-01-28 18:08 ` [PATCH v3 i-g-t 05/10] lib/igt_sriov_device: Add helper for PF/VF sysfs path formatting Marcin Bernatowicz
@ 2026-01-28 18:08 ` Marcin Bernatowicz
2026-01-29 8:21 ` Laguna, Lukasz
2026-01-28 18:08 ` [PATCH v3 i-g-t 07/10] tests/intel/xe_sriov_scheduling: Avoid assert on scheduling params restore in cleanup Marcin Bernatowicz
` (5 subsequent siblings)
11 siblings, 1 reply; 19+ messages in thread
From: Marcin Bernatowicz @ 2026-01-28 18:08 UTC (permalink / raw)
To: igt-dev
Cc: adam.miszczak, jakub1.kolakowski, lukasz.laguna, michal.wajdeczko,
Marcin Bernatowicz
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=y, Size: 22227 bytes --]
Reflect recent kernel changes and expose SR-IOV admin sysfs helpers for
scheduling control. Add per-VF and bulk accessors for execution quantum,
preemption timeout, scheduling priority, VF stop and restoring defaults.
Link: https://lore.kernel.org/intel-xe/20251030222348.186658-1-michal.wajdeczko@intel.com/
Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
Cc: Adam Miszczak <adam.miszczak@linux.intel.com>
Cc: Jakub Kolakowski <jakub1.kolakowski@intel.com>
Cc: Lukasz Laguna <lukasz.laguna@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
---
v2:
- Correct __xe_sriov_profile_set_exec_quantum_ms return code
on igt_sysfs_open() fail.
- Correct formatting.
- Rename helpers to consistent __xe_sriov_admin_*/xe_sriov_admin_*
Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
---
lib/meson.build | 1 +
lib/xe/xe_sriov_admin.c | 625 ++++++++++++++++++++++++++++++++++++++++
lib/xe/xe_sriov_admin.h | 60 ++++
3 files changed, 686 insertions(+)
create mode 100644 lib/xe/xe_sriov_admin.c
create mode 100644 lib/xe/xe_sriov_admin.h
diff --git a/lib/meson.build b/lib/meson.build
index 83569e8d2..d851029e0 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -128,6 +128,7 @@ lib_sources = [
'xe/xe_mmio.c',
'xe/xe_query.c',
'xe/xe_spin.c',
+ 'xe/xe_sriov_admin.c',
'xe/xe_sriov_debugfs.c',
'xe/xe_sriov_provisioning.c',
'xe/xe_util.c',
diff --git a/lib/xe/xe_sriov_admin.c b/lib/xe/xe_sriov_admin.c
new file mode 100644
index 000000000..f3be70db8
--- /dev/null
+++ b/lib/xe/xe_sriov_admin.c
@@ -0,0 +1,625 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright(c) 2025 Intel Corporation. All rights reserved.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "igt.h"
+#include "igt_sriov_device.h"
+#include "igt_sysfs.h"
+#include "igt_sysfs_choice.h"
+#include "xe_sriov_admin.h"
+
+static const char SRIOV_ADMIN[] = "device/sriov_admin";
+
+static int fmt_profile_rel_path(char *buf, size_t sz, unsigned int vf_num,
+ const char *attr)
+{
+ igt_assert(buf && attr && sz);
+
+ return snprintf(buf, sz, "%s/%s/%s", SRIOV_ADMIN, igt_sriov_func_str(vf_num), attr);
+}
+
+static int fmt_bulk_rel_path(char *buf, size_t sz, const char *attr)
+{
+ igt_assert(buf && attr && sz);
+
+ return snprintf(buf, sz, "%s/.bulk_profile/%s", SRIOV_ADMIN, attr);
+}
+
+static int ret_from_printf(int ret)
+{
+ return ret > 0 ? 0 : ret;
+}
+
+static int ret_from_scanf_items(int ret, int want_items)
+{
+ /* igt_sysfs_scanf: returns number of assigned items, or <0 on -errno */
+ if (ret < 0)
+ return ret;
+ return (ret == want_items) ? 0 : -EIO;
+}
+
+/**
+ * xe_sriov_admin_is_present - Check if SR-IOV admin sysfs interface is available
+ * @pf_fd: PF device file descriptor.
+ *
+ * Returns: true if the PF exposes the SR-IOV admin tree, false otherwise.
+ */
+bool xe_sriov_admin_is_present(int pf_fd)
+{
+ int sysfs;
+ bool ret;
+
+ sysfs = igt_sysfs_open(pf_fd);
+ if (sysfs < 0)
+ return -1;
+
+ ret = igt_sysfs_has_attr(sysfs, SRIOV_ADMIN);
+ close(sysfs);
+ return ret;
+}
+
+/**
+ * __xe_sriov_admin_set_exec_quantum_ms - Set execution quantum for a VF
+ * @pf_fd: PF device file descriptor.
+ * @vf_num: VF index (0 for PF, >0 for VFs).
+ * @eq_ms: Execution quantum in milliseconds.
+ *
+ * Writes the new execution quantum to sysfs.
+ *
+ * Returns: 0 on success or negative errno on error.
+ */
+int __xe_sriov_admin_set_exec_quantum_ms(int pf_fd, unsigned int vf_num,
+ uint32_t eq_ms)
+{
+ char path[PATH_MAX];
+ int sysfs;
+ bool ret;
+
+ sysfs = igt_sysfs_open(pf_fd);
+ if (sysfs < 0)
+ return sysfs;
+
+ fmt_profile_rel_path(path, sizeof(path), vf_num, "profile/exec_quantum_ms");
+ ret = igt_sysfs_printf(sysfs, path, "%u", eq_ms);
+ close(sysfs);
+
+ return ret_from_printf(ret);
+}
+
+/**
+ * xe_sriov_admin_set_exec_quantum_ms - Assert wrapper for setting VF execution quantum
+ * @pf_fd: PF device file descriptor.
+ * @vf_num: VF index (0 for PF, >0 for VFs).
+ * @eq_ms: Execution quantum in milliseconds.
+ *
+ * Calls __xe_sriov_admin_set_exec_quantum_ms() and asserts on error.
+ */
+void xe_sriov_admin_set_exec_quantum_ms(int pf_fd, unsigned int vf_num, uint32_t eq_ms)
+{
+ igt_assert_eq(0, __xe_sriov_admin_set_exec_quantum_ms(pf_fd, vf_num, eq_ms));
+}
+
+/**
+ * __xe_sriov_admin_get_exec_quantum_ms - Read execution quantum for a VF
+ * @pf_fd: PF device file descriptor.
+ * @vf_num: VF index (0 for PF, >0 for VFs).
+ * @eq_ms: Output pointer for the execution quantum (ms).
+ *
+ * Reads current VF execution quantum from sysfs.
+ *
+ * Returns: 0 on success or negative errno on error.
+ */
+int __xe_sriov_admin_get_exec_quantum_ms(int pf_fd, unsigned int vf_num, uint32_t *eq_ms)
+{
+ char path[PATH_MAX];
+ unsigned int val = 0;
+ int sysfs, ret;
+
+ sysfs = igt_sysfs_open(pf_fd);
+ if (sysfs < 0)
+ return sysfs;
+
+ fmt_profile_rel_path(path, sizeof(path), vf_num, "profile/exec_quantum_ms");
+ ret = igt_sysfs_scanf(sysfs, path, "%u", &val);
+ close(sysfs);
+
+ ret = ret_from_scanf_items(ret, 1);
+ if (ret)
+ return ret;
+
+ *eq_ms = val;
+ return 0;
+}
+
+/**
+ * xe_sriov_admin_get_exec_quantum_ms - Assert wrapper for reading VF execution quantum
+ * @pf_fd: PF device file descriptor.
+ * @vf_num: VF index (0 for PF, >0 for VFs).
+ *
+ * Returns: execution quantum (ms); asserts on error.
+ */
+uint32_t xe_sriov_admin_get_exec_quantum_ms(int pf_fd, unsigned int vf_num)
+{
+ uint32_t v = 0;
+
+ igt_assert_eq(0, __xe_sriov_admin_get_exec_quantum_ms(pf_fd, vf_num, &v));
+
+ return v;
+}
+
+/**
+ * __xe_sriov_admin_set_preempt_timeout_us - Set preemption timeout for a VF
+ * @pf_fd: PF device file descriptor.
+ * @vf_num: VF index (0 for PF, >0 for VFs).
+ * @pt_us: Preemption timeout in microseconds.
+ *
+ * Returns: 0 on success or negative errno on error.
+ */
+int __xe_sriov_admin_set_preempt_timeout_us(int pf_fd, unsigned int vf_num, uint32_t pt_us)
+{
+ char path[PATH_MAX];
+ int sysfs, ret;
+
+ sysfs = igt_sysfs_open(pf_fd);
+ if (sysfs < 0)
+ return sysfs;
+
+ fmt_profile_rel_path(path, sizeof(path), vf_num, "profile/preempt_timeout_us");
+ ret = igt_sysfs_printf(sysfs, path, "%u", pt_us);
+ close(sysfs);
+
+ return ret_from_printf(ret);
+}
+
+/**
+ * xe_sriov_admin_set_preempt_timeout_us - Assert wrapper for setting VF preemption timeout
+ * @pf_fd: PF device file descriptor.
+ * @vf_num: VF index (0 for PF, >0 for VFs).
+ * @pt_us: Preemption timeout in microseconds.
+ */
+void xe_sriov_admin_set_preempt_timeout_us(int pf_fd, unsigned int vf_num, uint32_t pt_us)
+{
+ igt_assert_eq(0, __xe_sriov_admin_set_preempt_timeout_us(pf_fd, vf_num, pt_us));
+}
+
+/**
+ * __xe_sriov_admin_get_preempt_timeout_us - Read preemption timeout for a VF
+ * @pf_fd: PF device file descriptor.
+ * @vf_num: VF index (0 for PF, >0 for VFs).
+ * @pt_us: Output pointer for preemption timeout (µs).
+ *
+ * Returns: 0 on success or negative errno on error.
+ */
+int __xe_sriov_admin_get_preempt_timeout_us(int pf_fd, unsigned int vf_num,
+ uint32_t *pt_us)
+{
+ char path[PATH_MAX];
+ unsigned int val = 0;
+ int sysfs, ret;
+
+ sysfs = igt_sysfs_open(pf_fd);
+ if (sysfs < 0)
+ return sysfs;
+
+ fmt_profile_rel_path(path, sizeof(path), vf_num,
+ "profile/preempt_timeout_us");
+ ret = igt_sysfs_scanf(sysfs, path, "%u", &val);
+ close(sysfs);
+
+ ret = ret_from_scanf_items(ret, 1);
+ if (ret)
+ return ret;
+ *pt_us = val;
+ return 0;
+}
+
+/**
+ * xe_sriov_admin_get_preempt_timeout_us - Assert wrapper for reading VF preemption timeout
+ * @pf_fd: PF device file descriptor.
+ * @vf_num: VF index (0 for PF, >0 for VFs).
+ *
+ * Returns: preemption timeout (µs); asserts on error.
+ */
+uint32_t xe_sriov_admin_get_preempt_timeout_us(int pf_fd, unsigned int vf_num)
+{
+ uint32_t v = 0;
+
+ igt_assert_eq(0, __xe_sriov_admin_get_preempt_timeout_us(pf_fd, vf_num, &v));
+ return v;
+}
+
+/**
+ * __xe_sriov_admin_set_sched_priority_string - Set VF priority from string
+ * @pf_fd: PF device file descriptor.
+ * @vf_num: VF index (0 for PF, >0 for VFs).
+ * @prio: String value ("low", "normal", "high").
+ *
+ * Returns: 0 on success or negative errno on error.
+ */
+int __xe_sriov_admin_set_sched_priority_string(int pf_fd, unsigned int vf_num,
+ const char *prio)
+{
+ char path[PATH_MAX];
+ int sysfs, ret;
+
+ if (!prio)
+ return -EINVAL;
+
+ sysfs = igt_sysfs_open(pf_fd);
+ if (sysfs < 0)
+ return sysfs;
+
+ fmt_profile_rel_path(path, sizeof(path), vf_num,
+ "profile/sched_priority");
+ ret = igt_sysfs_printf(sysfs, path, "%s", prio);
+ close(sysfs);
+ return ret_from_printf(ret);
+}
+
+/**
+ * __xe_sriov_admin_set_sched_priority - Set VF scheduling priority
+ * @pf_fd: PF device file descriptor.
+ * @vf_num: VF index (0 for PF, >0 for VFs).
+ * @prio: Priority enum value.
+ *
+ * Returns: 0 on success or negative errno on error.
+ */
+int __xe_sriov_admin_set_sched_priority(int pf_fd, unsigned int vf_num,
+ enum xe_sriov_sched_priority prio)
+{
+ const char *p = xe_sriov_sched_priority_to_string(prio);
+
+ return __xe_sriov_admin_set_sched_priority_string(pf_fd, vf_num, p);
+}
+
+/**
+ * xe_sriov_admin_set_sched_priority - Assert wrapper for setting VF priority
+ * @pf_fd: PF device file descriptor.
+ * @vf_num: VF index (0 for PF, >0 for VFs).
+ * @prio: Priority enum value.
+ */
+void xe_sriov_admin_set_sched_priority(int pf_fd, unsigned int vf_num,
+ enum xe_sriov_sched_priority prio)
+{
+ igt_assert_eq(0, __xe_sriov_admin_set_sched_priority(pf_fd, vf_num, prio));
+}
+
+/**
+ * __xe_sriov_admin_get_sched_priority_choice - Read sched_priority tokens
+ * @pf_fd: PF device file descriptor
+ * @vf_num: VF index (0 for PF, >0 for VFs).
+ * @choice: Output choice structure with parsed tokens and selected index
+ *
+ * Reads the sched_priority sysfs attribute for the given PF/VF and parses it
+ * into an igt_sysfs_choice.
+ *
+ * Returns: 0 on success or a negative errno code.
+ */
+int __xe_sriov_admin_get_sched_priority_choice(int pf_fd, unsigned int vf_num,
+ struct igt_sysfs_choice *choice)
+{
+ char path[PATH_MAX];
+ int sysfs, ret;
+
+ sysfs = igt_sysfs_open(pf_fd);
+ if (sysfs < 0)
+ return sysfs;
+
+ fmt_profile_rel_path(path, sizeof(path), vf_num, "profile/sched_priority");
+ ret = igt_sysfs_choice_read(sysfs, path, choice);
+ close(sysfs);
+
+ return ret;
+}
+
+/**
+ * __xe_sriov_admin_get_sched_priority - Read VF scheduling priority + mask
+ * @pf_fd: PF device file descriptor.
+ * @vf_num: VF index (0 for PF, >0 for VFs).
+ * @prio: Output pointer for the effective priority.
+ * @prio_mask: Output mask of allowed priorities.
+ *
+ * Returns: 0 on success or negative errno on error.
+ */
+int __xe_sriov_admin_get_sched_priority(int pf_fd, unsigned int vf_num,
+ enum xe_sriov_sched_priority *prio,
+ unsigned int *prio_mask)
+{
+ struct igt_sysfs_choice prio_ch = {};
+ int ret;
+
+ ret = __xe_sriov_admin_get_sched_priority_choice(pf_fd, vf_num, &prio_ch);
+ if (ret)
+ return ret;
+
+ ret = xe_sriov_sched_priority_from_string(prio_ch.tokens[prio_ch.selected], prio);
+ if (igt_debug_on_f(ret, "unknown selected value '%s' (err=%d)\n",
+ prio_ch.tokens[prio_ch.selected], ret))
+ return ret;
+
+ if (prio_mask) {
+ ret = xe_sriov_sched_priority_choice_to_mask(&prio_ch, prio_mask, NULL);
+ if (igt_debug_on_f(ret, "mask conversion failed (err=%d)\n", ret))
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * xe_sriov_admin_get_sched_priority - Assert wrapper for reading VF priority
+ * @pf_fd: PF device file descriptor.
+ * @vf_num: VF index (0 for PF, >0 for VFs).
+ * @prio_mask: Output mask of supported priorities.
+ *
+ * Returns: effective priority; asserts on error.
+ */
+enum xe_sriov_sched_priority
+xe_sriov_admin_get_sched_priority(int pf_fd, unsigned int vf_num,
+ unsigned int *prio_mask)
+{
+ enum xe_sriov_sched_priority cur_prio;
+
+ igt_assert_eq(0,
+ __xe_sriov_admin_get_sched_priority(pf_fd, vf_num, &cur_prio, prio_mask));
+
+ return cur_prio;
+}
+
+/**
+ * __xe_sriov_admin_bulk_set_exec_quantum_ms - Set execution quantum for PF and all VFs
+ * @pf_fd: PF device file descriptor.
+ * @eq_ms: Execution quantum in milliseconds.
+ *
+ * Applies the value to PF and all VFs.
+ *
+ * Returns: 0 on success or negative errno on error.
+ */
+int __xe_sriov_admin_bulk_set_exec_quantum_ms(int pf_fd, uint32_t eq_ms)
+{
+ char path[PATH_MAX];
+ int sysfs, ret;
+
+ sysfs = igt_sysfs_open(pf_fd);
+ if (sysfs < 0)
+ return sysfs;
+
+ fmt_bulk_rel_path(path, sizeof(path), "exec_quantum_ms");
+ ret = igt_sysfs_printf(sysfs, path, "%u", eq_ms);
+ close(sysfs);
+
+ return ret_from_printf(ret);
+}
+
+/**
+ * xe_sriov_admin_bulk_set_exec_quantum_ms - Assert wrapper for bulk execution quantum update
+ * @pf_fd: PF device file descriptor.
+ * @eq_ms: Execution quantum in milliseconds.
+ */
+void xe_sriov_admin_bulk_set_exec_quantum_ms(int pf_fd, uint32_t eq_ms)
+{
+ igt_assert_eq(0, __xe_sriov_admin_bulk_set_exec_quantum_ms(pf_fd, eq_ms));
+}
+
+/**
+ * __xe_sriov_admin_bulk_set_preempt_timeout_us - Set preemption timeout for PF and all VFs
+ * @pf_fd: PF device file descriptor.
+ * @pt_us: Preemption timeout in microseconds.
+ *
+ * Applies the value to PF and all VFs.
+ *
+ * Returns: 0 on success or negative errno on error.
+ */
+int __xe_sriov_admin_bulk_set_preempt_timeout_us(int pf_fd, uint32_t pt_us)
+{
+ char path[PATH_MAX];
+ int sysfs, ret;
+
+ sysfs = igt_sysfs_open(pf_fd);
+ if (sysfs < 0)
+ return sysfs;
+
+ fmt_bulk_rel_path(path, sizeof(path), "preempt_timeout_us");
+ ret = igt_sysfs_printf(sysfs, path, "%u", pt_us);
+ close(sysfs);
+
+ return ret_from_printf(ret);
+}
+
+/**
+ * xe_sriov_admin_bulk_set_preempt_timeout_us - Assert wrapper for bulk preemption timeout update
+ * @pf_fd: PF device file descriptor.
+ * @pt_us: Preemption timeout in microseconds.
+ */
+void xe_sriov_admin_bulk_set_preempt_timeout_us(int pf_fd, uint32_t pt_us)
+{
+ igt_assert_eq(0, __xe_sriov_admin_bulk_set_preempt_timeout_us(pf_fd, pt_us));
+}
+
+/**
+ * __xe_sriov_admin_bulk_set_sched_priority_string - Set scheduling priority for PF and all VFs
+ * @pf_fd: PF device file descriptor.
+ * @prio: String priority ("low", "normal", "high").
+ *
+ * Returns: 0 on success or negative errno on error.
+ */
+int __xe_sriov_admin_bulk_set_sched_priority_string(int pf_fd, const char *prio)
+{
+ char path[PATH_MAX];
+ int sysfs, ret;
+
+ sysfs = igt_sysfs_open(pf_fd);
+ if (sysfs < 0)
+ return sysfs;
+
+ fmt_bulk_rel_path(path, sizeof(path), "sched_priority");
+ ret = igt_sysfs_printf(sysfs, path, "%s", prio);
+ close(sysfs);
+
+ return ret_from_printf(ret);
+}
+
+/**
+ * xe_sriov_admin_bulk_set_sched_priority_string - Assert wrapper for bulk priority update
+ * @pf_fd: PF device file descriptor.
+ * @prio: String priority.
+ */
+void xe_sriov_admin_bulk_set_sched_priority_string(int pf_fd, const char *prio)
+{
+ igt_assert_eq(0, __xe_sriov_admin_bulk_set_sched_priority_string(pf_fd, prio));
+}
+
+/**
+ * __xe_sriov_admin_bulk_set_sched_priority - Set numeric priority for PF and all VFs
+ * @pf_fd: PF device file descriptor.
+ * @prio: Enum priority value.
+ *
+ * Returns: 0 on success or negative errno on error.
+ */
+int __xe_sriov_admin_bulk_set_sched_priority(int pf_fd,
+ enum xe_sriov_sched_priority prio)
+{
+ const char *s = xe_sriov_sched_priority_to_string(prio);
+
+ if (!s)
+ return -EINVAL;
+ return __xe_sriov_admin_bulk_set_sched_priority_string(pf_fd, s);
+}
+
+/**
+ * xe_sriov_admin_bulk_set_sched_priority - Assert wrapper for bulk priority update
+ * @pf_fd: PF device file descriptor.
+ * @prio: Enum priority value.
+ */
+void xe_sriov_admin_bulk_set_sched_priority(int pf_fd,
+ enum xe_sriov_sched_priority prio)
+{
+ igt_assert_eq(0, __xe_sriov_admin_bulk_set_sched_priority(pf_fd, prio));
+}
+
+/**
+ * __xe_sriov_admin_vf_stop - Issue stop command for a VF
+ * @pf_fd: PF device file descriptor.
+ * @vf_num: VF index.
+ *
+ * Triggers VF stop via sysfs.
+ *
+ * Returns: 0 on success or negative errno on error.
+ */
+int __xe_sriov_admin_vf_stop(int pf_fd, unsigned int vf_num)
+{
+ char path[PATH_MAX];
+ int sysfs, ret;
+
+ sysfs = igt_sysfs_open(pf_fd);
+ if (sysfs < 0)
+ return sysfs;
+
+ fmt_profile_rel_path(path, sizeof(path), vf_num, "stop");
+ ret = igt_sysfs_printf(sysfs, path, "%u", 1u);
+ close(sysfs);
+
+ return ret_from_printf(ret);
+}
+
+/**
+ * xe_sriov_admin_vf_stop - Assert wrapper for VF stop command
+ * @pf_fd: PF device file descriptor.
+ * @vf_num: VF index.
+ */
+void xe_sriov_admin_vf_stop(int pf_fd, unsigned int vf_num)
+{
+ igt_assert_eq(0, __xe_sriov_admin_vf_stop(pf_fd, vf_num));
+}
+
+/**
+ * __xe_sriov_admin_restore_defaults - Restore scheduling defaults for a VF
+ * @pf_fd: PF device file descriptor.
+ * @vf_num: VF index (0 for PF, >0 for VFs).
+ *
+ * Resets execution quantum, preemption timeout, and priority to driver defaults.
+ *
+ * Returns: 0 on success or negative errno on error.
+ */
+int __xe_sriov_admin_restore_defaults(int pf_fd, unsigned int vf_num)
+{
+ int ret_eq, ret_pt, ret_prio;
+ int ret = 0;
+
+ ret_eq = __xe_sriov_admin_set_exec_quantum_ms(pf_fd, vf_num, 0);
+ igt_warn_on(ret_eq);
+ if (!ret)
+ ret = ret_eq;
+
+ ret_pt = __xe_sriov_admin_set_preempt_timeout_us(pf_fd, vf_num, 0);
+ igt_warn_on(ret_pt);
+ if (!ret)
+ ret = ret_pt;
+
+ ret_prio = __xe_sriov_admin_set_sched_priority(pf_fd, vf_num,
+ XE_SRIOV_SCHED_PRIORITY_LOW);
+ igt_warn_on(ret_prio);
+ if (!ret)
+ ret = ret_prio;
+
+ return ret;
+}
+
+/**
+ * xe_sriov_admin_restore_defaults - Assert wrapper restoring VF defaults
+ * @pf_fd: PF device file descriptor.
+ * @vf_num: VF index (0 for PF, >0 for VFs).
+ */
+void xe_sriov_admin_restore_defaults(int pf_fd, unsigned int vf_num)
+{
+ igt_assert_eq(0, __xe_sriov_admin_restore_defaults(pf_fd, vf_num));
+}
+
+/**
+ * __xe_sriov_admin_bulk_restore_defaults - Restore scheduling defaults for PF and all VFs
+ * @pf_fd: PF device file descriptor.
+ *
+ * Resets PF and all VFs to driver default scheduling parameters.
+ *
+ * Returns: 0 on success or negative errno on error.
+ */
+int __xe_sriov_admin_bulk_restore_defaults(int pf_fd)
+{
+ int ret_eq, ret_pt, ret_prio;
+ int ret = 0;
+
+ ret_eq = __xe_sriov_admin_bulk_set_exec_quantum_ms(pf_fd, 0);
+ igt_warn_on(ret_eq);
+ if (!ret)
+ ret = ret_eq;
+
+ ret_pt = __xe_sriov_admin_bulk_set_preempt_timeout_us(pf_fd, 0);
+ igt_warn_on(ret_pt);
+ if (!ret)
+ ret = ret_pt;
+
+ ret_prio = __xe_sriov_admin_bulk_set_sched_priority(pf_fd,
+ XE_SRIOV_SCHED_PRIORITY_LOW);
+ igt_warn_on(ret_prio);
+ if (!ret)
+ ret = ret_prio;
+
+ return ret;
+}
+
+/**
+ * xe_sriov_admin_bulk_restore_defaults - Assert wrapper for restoring defaults on PF and all VFs
+ * @pf_fd: PF device file descriptor.
+ */
+void xe_sriov_admin_bulk_restore_defaults(int pf_fd)
+{
+ igt_assert_eq(0, __xe_sriov_admin_bulk_restore_defaults(pf_fd));
+}
diff --git a/lib/xe/xe_sriov_admin.h b/lib/xe/xe_sriov_admin.h
new file mode 100644
index 000000000..607e33a86
--- /dev/null
+++ b/lib/xe/xe_sriov_admin.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright(c) 2025 Intel Corporation. All rights reserved.
+ */
+
+#ifndef __XE_SRIOV_ADMIN_H__
+#define __XE_SRIOV_ADMIN_H__
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stddef.h>
+#include "xe_sriov_provisioning.h" /* for enum xe_sriov_sched_priority */
+
+struct igt_sysfs_choice;
+
+bool xe_sriov_admin_is_present(int pf_fd);
+
+int __xe_sriov_admin_set_exec_quantum_ms(int pf_fd, unsigned int vf_num, uint32_t eq_ms);
+void xe_sriov_admin_set_exec_quantum_ms(int pf_fd, unsigned int vf_num, uint32_t eq_ms);
+int __xe_sriov_admin_get_exec_quantum_ms(int pf_fd, unsigned int vf_num, uint32_t *eq_ms);
+uint32_t xe_sriov_admin_get_exec_quantum_ms(int pf_fd, unsigned int vf_num);
+int __xe_sriov_admin_set_preempt_timeout_us(int pf_fd, unsigned int vf_num, uint32_t pt_us);
+void xe_sriov_admin_set_preempt_timeout_us(int pf_fd, unsigned int vf_num, uint32_t pt_us);
+int __xe_sriov_admin_get_preempt_timeout_us(int pf_fd, unsigned int vf_num, uint32_t *pt_us);
+uint32_t xe_sriov_admin_get_preempt_timeout_us(int pf_fd, unsigned int vf_num);
+int __xe_sriov_admin_set_sched_priority_string(int pf_fd, unsigned int vf_num,
+ const char *prio);
+int __xe_sriov_admin_get_sched_priority_choice(int pf_fd, unsigned int vf_num,
+ struct igt_sysfs_choice *choice);
+int __xe_sriov_admin_set_sched_priority(int pf_fd, unsigned int vf_num,
+ enum xe_sriov_sched_priority prio);
+void xe_sriov_admin_set_sched_priority(int pf_fd, unsigned int vf_num,
+ enum xe_sriov_sched_priority prio);
+int __xe_sriov_admin_get_sched_priority(int pf_fd, unsigned int vf_num,
+ enum xe_sriov_sched_priority *prio,
+ unsigned int *prio_mask);
+enum xe_sriov_sched_priority
+xe_sriov_admin_get_sched_priority(int pf_fd, unsigned int vf_num,
+ unsigned int *prio_mask);
+
+int __xe_sriov_admin_bulk_set_exec_quantum_ms(int pf_fd, uint32_t eq_ms);
+void xe_sriov_admin_bulk_set_exec_quantum_ms(int pf_fd, uint32_t eq_ms);
+int __xe_sriov_admin_bulk_set_preempt_timeout_us(int pf_fd, uint32_t pt_us);
+void xe_sriov_admin_bulk_set_preempt_timeout_us(int pf_fd, uint32_t pt_us);
+int __xe_sriov_admin_bulk_set_sched_priority_string(int pf_fd, const char *prio);
+void xe_sriov_admin_bulk_set_sched_priority_string(int pf_fd, const char *prio);
+int __xe_sriov_admin_bulk_set_sched_priority(int pf_fd,
+ enum xe_sriov_sched_priority prio);
+void xe_sriov_admin_bulk_set_sched_priority(int pf_fd,
+ enum xe_sriov_sched_priority prio);
+
+int __xe_sriov_admin_vf_stop(int pf_fd, unsigned int vf_num);
+void xe_sriov_admin_vf_stop(int pf_fd, unsigned int vf_num);
+
+int __xe_sriov_admin_restore_defaults(int pf_fd, unsigned int vf_num);
+void xe_sriov_admin_restore_defaults(int pf_fd, unsigned int vf_num);
+int __xe_sriov_admin_bulk_restore_defaults(int pf_fd);
+void xe_sriov_admin_bulk_restore_defaults(int pf_fd);
+
+#endif /* __XE_SRIOV_ADMIN_H__ */
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* Re: [PATCH v3 i-g-t 06/10] lib/xe/xe_sriov_admin: Add SR-IOV admin sysfs accessors
2026-01-28 18:08 ` [PATCH v3 i-g-t 06/10] lib/xe/xe_sriov_admin: Add SR-IOV admin sysfs accessors Marcin Bernatowicz
@ 2026-01-29 8:21 ` Laguna, Lukasz
0 siblings, 0 replies; 19+ messages in thread
From: Laguna, Lukasz @ 2026-01-29 8:21 UTC (permalink / raw)
To: Marcin Bernatowicz, igt-dev
Cc: adam.miszczak, jakub1.kolakowski, michal.wajdeczko
On 1/28/2026 19:08, Marcin Bernatowicz wrote:
> Reflect recent kernel changes and expose SR-IOV admin sysfs helpers for
> scheduling control. Add per-VF and bulk accessors for execution quantum,
> preemption timeout, scheduling priority, VF stop and restoring defaults.
>
> Link: https://lore.kernel.org/intel-xe/20251030222348.186658-1-michal.wajdeczko@intel.com/
> Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
> Cc: Adam Miszczak <adam.miszczak@linux.intel.com>
> Cc: Jakub Kolakowski <jakub1.kolakowski@intel.com>
> Cc: Lukasz Laguna <lukasz.laguna@intel.com>
Reviewed-by: Lukasz Laguna <lukasz.laguna@intel.com>
> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
>
> ---
> v2:
> - Correct __xe_sriov_profile_set_exec_quantum_ms return code
> on igt_sysfs_open() fail.
> - Correct formatting.
> - Rename helpers to consistent __xe_sriov_admin_*/xe_sriov_admin_*
>
> Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
> ---
> lib/meson.build | 1 +
> lib/xe/xe_sriov_admin.c | 625 ++++++++++++++++++++++++++++++++++++++++
> lib/xe/xe_sriov_admin.h | 60 ++++
> 3 files changed, 686 insertions(+)
> create mode 100644 lib/xe/xe_sriov_admin.c
> create mode 100644 lib/xe/xe_sriov_admin.h
>
> diff --git a/lib/meson.build b/lib/meson.build
> index 83569e8d2..d851029e0 100644
> --- a/lib/meson.build
> +++ b/lib/meson.build
> @@ -128,6 +128,7 @@ lib_sources = [
> 'xe/xe_mmio.c',
> 'xe/xe_query.c',
> 'xe/xe_spin.c',
> + 'xe/xe_sriov_admin.c',
> 'xe/xe_sriov_debugfs.c',
> 'xe/xe_sriov_provisioning.c',
> 'xe/xe_util.c',
> diff --git a/lib/xe/xe_sriov_admin.c b/lib/xe/xe_sriov_admin.c
> new file mode 100644
> index 000000000..f3be70db8
> --- /dev/null
> +++ b/lib/xe/xe_sriov_admin.c
> @@ -0,0 +1,625 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright(c) 2025 Intel Corporation. All rights reserved.
> + */
> +
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <limits.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include "igt.h"
> +#include "igt_sriov_device.h"
> +#include "igt_sysfs.h"
> +#include "igt_sysfs_choice.h"
> +#include "xe_sriov_admin.h"
> +
> +static const char SRIOV_ADMIN[] = "device/sriov_admin";
> +
> +static int fmt_profile_rel_path(char *buf, size_t sz, unsigned int vf_num,
> + const char *attr)
> +{
> + igt_assert(buf && attr && sz);
> +
> + return snprintf(buf, sz, "%s/%s/%s", SRIOV_ADMIN, igt_sriov_func_str(vf_num), attr);
> +}
> +
> +static int fmt_bulk_rel_path(char *buf, size_t sz, const char *attr)
> +{
> + igt_assert(buf && attr && sz);
> +
> + return snprintf(buf, sz, "%s/.bulk_profile/%s", SRIOV_ADMIN, attr);
> +}
> +
> +static int ret_from_printf(int ret)
> +{
> + return ret > 0 ? 0 : ret;
> +}
> +
> +static int ret_from_scanf_items(int ret, int want_items)
> +{
> + /* igt_sysfs_scanf: returns number of assigned items, or <0 on -errno */
> + if (ret < 0)
> + return ret;
> + return (ret == want_items) ? 0 : -EIO;
> +}
> +
> +/**
> + * xe_sriov_admin_is_present - Check if SR-IOV admin sysfs interface is available
> + * @pf_fd: PF device file descriptor.
> + *
> + * Returns: true if the PF exposes the SR-IOV admin tree, false otherwise.
> + */
> +bool xe_sriov_admin_is_present(int pf_fd)
> +{
> + int sysfs;
> + bool ret;
> +
> + sysfs = igt_sysfs_open(pf_fd);
> + if (sysfs < 0)
> + return -1;
> +
> + ret = igt_sysfs_has_attr(sysfs, SRIOV_ADMIN);
> + close(sysfs);
> + return ret;
> +}
> +
> +/**
> + * __xe_sriov_admin_set_exec_quantum_ms - Set execution quantum for a VF
> + * @pf_fd: PF device file descriptor.
> + * @vf_num: VF index (0 for PF, >0 for VFs).
> + * @eq_ms: Execution quantum in milliseconds.
> + *
> + * Writes the new execution quantum to sysfs.
> + *
> + * Returns: 0 on success or negative errno on error.
> + */
> +int __xe_sriov_admin_set_exec_quantum_ms(int pf_fd, unsigned int vf_num,
> + uint32_t eq_ms)
> +{
> + char path[PATH_MAX];
> + int sysfs;
> + bool ret;
> +
> + sysfs = igt_sysfs_open(pf_fd);
> + if (sysfs < 0)
> + return sysfs;
> +
> + fmt_profile_rel_path(path, sizeof(path), vf_num, "profile/exec_quantum_ms");
> + ret = igt_sysfs_printf(sysfs, path, "%u", eq_ms);
> + close(sysfs);
> +
> + return ret_from_printf(ret);
> +}
> +
> +/**
> + * xe_sriov_admin_set_exec_quantum_ms - Assert wrapper for setting VF execution quantum
> + * @pf_fd: PF device file descriptor.
> + * @vf_num: VF index (0 for PF, >0 for VFs).
> + * @eq_ms: Execution quantum in milliseconds.
> + *
> + * Calls __xe_sriov_admin_set_exec_quantum_ms() and asserts on error.
> + */
> +void xe_sriov_admin_set_exec_quantum_ms(int pf_fd, unsigned int vf_num, uint32_t eq_ms)
> +{
> + igt_assert_eq(0, __xe_sriov_admin_set_exec_quantum_ms(pf_fd, vf_num, eq_ms));
> +}
> +
> +/**
> + * __xe_sriov_admin_get_exec_quantum_ms - Read execution quantum for a VF
> + * @pf_fd: PF device file descriptor.
> + * @vf_num: VF index (0 for PF, >0 for VFs).
> + * @eq_ms: Output pointer for the execution quantum (ms).
> + *
> + * Reads current VF execution quantum from sysfs.
> + *
> + * Returns: 0 on success or negative errno on error.
> + */
> +int __xe_sriov_admin_get_exec_quantum_ms(int pf_fd, unsigned int vf_num, uint32_t *eq_ms)
> +{
> + char path[PATH_MAX];
> + unsigned int val = 0;
> + int sysfs, ret;
> +
> + sysfs = igt_sysfs_open(pf_fd);
> + if (sysfs < 0)
> + return sysfs;
> +
> + fmt_profile_rel_path(path, sizeof(path), vf_num, "profile/exec_quantum_ms");
> + ret = igt_sysfs_scanf(sysfs, path, "%u", &val);
> + close(sysfs);
> +
> + ret = ret_from_scanf_items(ret, 1);
> + if (ret)
> + return ret;
> +
> + *eq_ms = val;
> + return 0;
> +}
> +
> +/**
> + * xe_sriov_admin_get_exec_quantum_ms - Assert wrapper for reading VF execution quantum
> + * @pf_fd: PF device file descriptor.
> + * @vf_num: VF index (0 for PF, >0 for VFs).
> + *
> + * Returns: execution quantum (ms); asserts on error.
> + */
> +uint32_t xe_sriov_admin_get_exec_quantum_ms(int pf_fd, unsigned int vf_num)
> +{
> + uint32_t v = 0;
> +
> + igt_assert_eq(0, __xe_sriov_admin_get_exec_quantum_ms(pf_fd, vf_num, &v));
> +
> + return v;
> +}
> +
> +/**
> + * __xe_sriov_admin_set_preempt_timeout_us - Set preemption timeout for a VF
> + * @pf_fd: PF device file descriptor.
> + * @vf_num: VF index (0 for PF, >0 for VFs).
> + * @pt_us: Preemption timeout in microseconds.
> + *
> + * Returns: 0 on success or negative errno on error.
> + */
> +int __xe_sriov_admin_set_preempt_timeout_us(int pf_fd, unsigned int vf_num, uint32_t pt_us)
> +{
> + char path[PATH_MAX];
> + int sysfs, ret;
> +
> + sysfs = igt_sysfs_open(pf_fd);
> + if (sysfs < 0)
> + return sysfs;
> +
> + fmt_profile_rel_path(path, sizeof(path), vf_num, "profile/preempt_timeout_us");
> + ret = igt_sysfs_printf(sysfs, path, "%u", pt_us);
> + close(sysfs);
> +
> + return ret_from_printf(ret);
> +}
> +
> +/**
> + * xe_sriov_admin_set_preempt_timeout_us - Assert wrapper for setting VF preemption timeout
> + * @pf_fd: PF device file descriptor.
> + * @vf_num: VF index (0 for PF, >0 for VFs).
> + * @pt_us: Preemption timeout in microseconds.
> + */
> +void xe_sriov_admin_set_preempt_timeout_us(int pf_fd, unsigned int vf_num, uint32_t pt_us)
> +{
> + igt_assert_eq(0, __xe_sriov_admin_set_preempt_timeout_us(pf_fd, vf_num, pt_us));
> +}
> +
> +/**
> + * __xe_sriov_admin_get_preempt_timeout_us - Read preemption timeout for a VF
> + * @pf_fd: PF device file descriptor.
> + * @vf_num: VF index (0 for PF, >0 for VFs).
> + * @pt_us: Output pointer for preemption timeout (µs).
> + *
> + * Returns: 0 on success or negative errno on error.
> + */
> +int __xe_sriov_admin_get_preempt_timeout_us(int pf_fd, unsigned int vf_num,
> + uint32_t *pt_us)
> +{
> + char path[PATH_MAX];
> + unsigned int val = 0;
> + int sysfs, ret;
> +
> + sysfs = igt_sysfs_open(pf_fd);
> + if (sysfs < 0)
> + return sysfs;
> +
> + fmt_profile_rel_path(path, sizeof(path), vf_num,
> + "profile/preempt_timeout_us");
> + ret = igt_sysfs_scanf(sysfs, path, "%u", &val);
> + close(sysfs);
> +
> + ret = ret_from_scanf_items(ret, 1);
> + if (ret)
> + return ret;
> + *pt_us = val;
> + return 0;
> +}
> +
> +/**
> + * xe_sriov_admin_get_preempt_timeout_us - Assert wrapper for reading VF preemption timeout
> + * @pf_fd: PF device file descriptor.
> + * @vf_num: VF index (0 for PF, >0 for VFs).
> + *
> + * Returns: preemption timeout (µs); asserts on error.
> + */
> +uint32_t xe_sriov_admin_get_preempt_timeout_us(int pf_fd, unsigned int vf_num)
> +{
> + uint32_t v = 0;
> +
> + igt_assert_eq(0, __xe_sriov_admin_get_preempt_timeout_us(pf_fd, vf_num, &v));
> + return v;
> +}
> +
> +/**
> + * __xe_sriov_admin_set_sched_priority_string - Set VF priority from string
> + * @pf_fd: PF device file descriptor.
> + * @vf_num: VF index (0 for PF, >0 for VFs).
> + * @prio: String value ("low", "normal", "high").
> + *
> + * Returns: 0 on success or negative errno on error.
> + */
> +int __xe_sriov_admin_set_sched_priority_string(int pf_fd, unsigned int vf_num,
> + const char *prio)
> +{
> + char path[PATH_MAX];
> + int sysfs, ret;
> +
> + if (!prio)
> + return -EINVAL;
> +
> + sysfs = igt_sysfs_open(pf_fd);
> + if (sysfs < 0)
> + return sysfs;
> +
> + fmt_profile_rel_path(path, sizeof(path), vf_num,
> + "profile/sched_priority");
> + ret = igt_sysfs_printf(sysfs, path, "%s", prio);
> + close(sysfs);
> + return ret_from_printf(ret);
> +}
> +
> +/**
> + * __xe_sriov_admin_set_sched_priority - Set VF scheduling priority
> + * @pf_fd: PF device file descriptor.
> + * @vf_num: VF index (0 for PF, >0 for VFs).
> + * @prio: Priority enum value.
> + *
> + * Returns: 0 on success or negative errno on error.
> + */
> +int __xe_sriov_admin_set_sched_priority(int pf_fd, unsigned int vf_num,
> + enum xe_sriov_sched_priority prio)
> +{
> + const char *p = xe_sriov_sched_priority_to_string(prio);
> +
> + return __xe_sriov_admin_set_sched_priority_string(pf_fd, vf_num, p);
> +}
> +
> +/**
> + * xe_sriov_admin_set_sched_priority - Assert wrapper for setting VF priority
> + * @pf_fd: PF device file descriptor.
> + * @vf_num: VF index (0 for PF, >0 for VFs).
> + * @prio: Priority enum value.
> + */
> +void xe_sriov_admin_set_sched_priority(int pf_fd, unsigned int vf_num,
> + enum xe_sriov_sched_priority prio)
> +{
> + igt_assert_eq(0, __xe_sriov_admin_set_sched_priority(pf_fd, vf_num, prio));
> +}
> +
> +/**
> + * __xe_sriov_admin_get_sched_priority_choice - Read sched_priority tokens
> + * @pf_fd: PF device file descriptor
> + * @vf_num: VF index (0 for PF, >0 for VFs).
> + * @choice: Output choice structure with parsed tokens and selected index
> + *
> + * Reads the sched_priority sysfs attribute for the given PF/VF and parses it
> + * into an igt_sysfs_choice.
> + *
> + * Returns: 0 on success or a negative errno code.
> + */
> +int __xe_sriov_admin_get_sched_priority_choice(int pf_fd, unsigned int vf_num,
> + struct igt_sysfs_choice *choice)
> +{
> + char path[PATH_MAX];
> + int sysfs, ret;
> +
> + sysfs = igt_sysfs_open(pf_fd);
> + if (sysfs < 0)
> + return sysfs;
> +
> + fmt_profile_rel_path(path, sizeof(path), vf_num, "profile/sched_priority");
> + ret = igt_sysfs_choice_read(sysfs, path, choice);
> + close(sysfs);
> +
> + return ret;
> +}
> +
> +/**
> + * __xe_sriov_admin_get_sched_priority - Read VF scheduling priority + mask
> + * @pf_fd: PF device file descriptor.
> + * @vf_num: VF index (0 for PF, >0 for VFs).
> + * @prio: Output pointer for the effective priority.
> + * @prio_mask: Output mask of allowed priorities.
> + *
> + * Returns: 0 on success or negative errno on error.
> + */
> +int __xe_sriov_admin_get_sched_priority(int pf_fd, unsigned int vf_num,
> + enum xe_sriov_sched_priority *prio,
> + unsigned int *prio_mask)
> +{
> + struct igt_sysfs_choice prio_ch = {};
> + int ret;
> +
> + ret = __xe_sriov_admin_get_sched_priority_choice(pf_fd, vf_num, &prio_ch);
> + if (ret)
> + return ret;
> +
> + ret = xe_sriov_sched_priority_from_string(prio_ch.tokens[prio_ch.selected], prio);
> + if (igt_debug_on_f(ret, "unknown selected value '%s' (err=%d)\n",
> + prio_ch.tokens[prio_ch.selected], ret))
> + return ret;
> +
> + if (prio_mask) {
> + ret = xe_sriov_sched_priority_choice_to_mask(&prio_ch, prio_mask, NULL);
> + if (igt_debug_on_f(ret, "mask conversion failed (err=%d)\n", ret))
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +/**
> + * xe_sriov_admin_get_sched_priority - Assert wrapper for reading VF priority
> + * @pf_fd: PF device file descriptor.
> + * @vf_num: VF index (0 for PF, >0 for VFs).
> + * @prio_mask: Output mask of supported priorities.
> + *
> + * Returns: effective priority; asserts on error.
> + */
> +enum xe_sriov_sched_priority
> +xe_sriov_admin_get_sched_priority(int pf_fd, unsigned int vf_num,
> + unsigned int *prio_mask)
> +{
> + enum xe_sriov_sched_priority cur_prio;
> +
> + igt_assert_eq(0,
> + __xe_sriov_admin_get_sched_priority(pf_fd, vf_num, &cur_prio, prio_mask));
> +
> + return cur_prio;
> +}
> +
> +/**
> + * __xe_sriov_admin_bulk_set_exec_quantum_ms - Set execution quantum for PF and all VFs
> + * @pf_fd: PF device file descriptor.
> + * @eq_ms: Execution quantum in milliseconds.
> + *
> + * Applies the value to PF and all VFs.
> + *
> + * Returns: 0 on success or negative errno on error.
> + */
> +int __xe_sriov_admin_bulk_set_exec_quantum_ms(int pf_fd, uint32_t eq_ms)
> +{
> + char path[PATH_MAX];
> + int sysfs, ret;
> +
> + sysfs = igt_sysfs_open(pf_fd);
> + if (sysfs < 0)
> + return sysfs;
> +
> + fmt_bulk_rel_path(path, sizeof(path), "exec_quantum_ms");
> + ret = igt_sysfs_printf(sysfs, path, "%u", eq_ms);
> + close(sysfs);
> +
> + return ret_from_printf(ret);
> +}
> +
> +/**
> + * xe_sriov_admin_bulk_set_exec_quantum_ms - Assert wrapper for bulk execution quantum update
> + * @pf_fd: PF device file descriptor.
> + * @eq_ms: Execution quantum in milliseconds.
> + */
> +void xe_sriov_admin_bulk_set_exec_quantum_ms(int pf_fd, uint32_t eq_ms)
> +{
> + igt_assert_eq(0, __xe_sriov_admin_bulk_set_exec_quantum_ms(pf_fd, eq_ms));
> +}
> +
> +/**
> + * __xe_sriov_admin_bulk_set_preempt_timeout_us - Set preemption timeout for PF and all VFs
> + * @pf_fd: PF device file descriptor.
> + * @pt_us: Preemption timeout in microseconds.
> + *
> + * Applies the value to PF and all VFs.
> + *
> + * Returns: 0 on success or negative errno on error.
> + */
> +int __xe_sriov_admin_bulk_set_preempt_timeout_us(int pf_fd, uint32_t pt_us)
> +{
> + char path[PATH_MAX];
> + int sysfs, ret;
> +
> + sysfs = igt_sysfs_open(pf_fd);
> + if (sysfs < 0)
> + return sysfs;
> +
> + fmt_bulk_rel_path(path, sizeof(path), "preempt_timeout_us");
> + ret = igt_sysfs_printf(sysfs, path, "%u", pt_us);
> + close(sysfs);
> +
> + return ret_from_printf(ret);
> +}
> +
> +/**
> + * xe_sriov_admin_bulk_set_preempt_timeout_us - Assert wrapper for bulk preemption timeout update
> + * @pf_fd: PF device file descriptor.
> + * @pt_us: Preemption timeout in microseconds.
> + */
> +void xe_sriov_admin_bulk_set_preempt_timeout_us(int pf_fd, uint32_t pt_us)
> +{
> + igt_assert_eq(0, __xe_sriov_admin_bulk_set_preempt_timeout_us(pf_fd, pt_us));
> +}
> +
> +/**
> + * __xe_sriov_admin_bulk_set_sched_priority_string - Set scheduling priority for PF and all VFs
> + * @pf_fd: PF device file descriptor.
> + * @prio: String priority ("low", "normal", "high").
> + *
> + * Returns: 0 on success or negative errno on error.
> + */
> +int __xe_sriov_admin_bulk_set_sched_priority_string(int pf_fd, const char *prio)
> +{
> + char path[PATH_MAX];
> + int sysfs, ret;
> +
> + sysfs = igt_sysfs_open(pf_fd);
> + if (sysfs < 0)
> + return sysfs;
> +
> + fmt_bulk_rel_path(path, sizeof(path), "sched_priority");
> + ret = igt_sysfs_printf(sysfs, path, "%s", prio);
> + close(sysfs);
> +
> + return ret_from_printf(ret);
> +}
> +
> +/**
> + * xe_sriov_admin_bulk_set_sched_priority_string - Assert wrapper for bulk priority update
> + * @pf_fd: PF device file descriptor.
> + * @prio: String priority.
> + */
> +void xe_sriov_admin_bulk_set_sched_priority_string(int pf_fd, const char *prio)
> +{
> + igt_assert_eq(0, __xe_sriov_admin_bulk_set_sched_priority_string(pf_fd, prio));
> +}
> +
> +/**
> + * __xe_sriov_admin_bulk_set_sched_priority - Set numeric priority for PF and all VFs
> + * @pf_fd: PF device file descriptor.
> + * @prio: Enum priority value.
> + *
> + * Returns: 0 on success or negative errno on error.
> + */
> +int __xe_sriov_admin_bulk_set_sched_priority(int pf_fd,
> + enum xe_sriov_sched_priority prio)
> +{
> + const char *s = xe_sriov_sched_priority_to_string(prio);
> +
> + if (!s)
> + return -EINVAL;
> + return __xe_sriov_admin_bulk_set_sched_priority_string(pf_fd, s);
> +}
> +
> +/**
> + * xe_sriov_admin_bulk_set_sched_priority - Assert wrapper for bulk priority update
> + * @pf_fd: PF device file descriptor.
> + * @prio: Enum priority value.
> + */
> +void xe_sriov_admin_bulk_set_sched_priority(int pf_fd,
> + enum xe_sriov_sched_priority prio)
> +{
> + igt_assert_eq(0, __xe_sriov_admin_bulk_set_sched_priority(pf_fd, prio));
> +}
> +
> +/**
> + * __xe_sriov_admin_vf_stop - Issue stop command for a VF
> + * @pf_fd: PF device file descriptor.
> + * @vf_num: VF index.
> + *
> + * Triggers VF stop via sysfs.
> + *
> + * Returns: 0 on success or negative errno on error.
> + */
> +int __xe_sriov_admin_vf_stop(int pf_fd, unsigned int vf_num)
> +{
> + char path[PATH_MAX];
> + int sysfs, ret;
> +
> + sysfs = igt_sysfs_open(pf_fd);
> + if (sysfs < 0)
> + return sysfs;
> +
> + fmt_profile_rel_path(path, sizeof(path), vf_num, "stop");
> + ret = igt_sysfs_printf(sysfs, path, "%u", 1u);
> + close(sysfs);
> +
> + return ret_from_printf(ret);
> +}
> +
> +/**
> + * xe_sriov_admin_vf_stop - Assert wrapper for VF stop command
> + * @pf_fd: PF device file descriptor.
> + * @vf_num: VF index.
> + */
> +void xe_sriov_admin_vf_stop(int pf_fd, unsigned int vf_num)
> +{
> + igt_assert_eq(0, __xe_sriov_admin_vf_stop(pf_fd, vf_num));
> +}
> +
> +/**
> + * __xe_sriov_admin_restore_defaults - Restore scheduling defaults for a VF
> + * @pf_fd: PF device file descriptor.
> + * @vf_num: VF index (0 for PF, >0 for VFs).
> + *
> + * Resets execution quantum, preemption timeout, and priority to driver defaults.
> + *
> + * Returns: 0 on success or negative errno on error.
> + */
> +int __xe_sriov_admin_restore_defaults(int pf_fd, unsigned int vf_num)
> +{
> + int ret_eq, ret_pt, ret_prio;
> + int ret = 0;
> +
> + ret_eq = __xe_sriov_admin_set_exec_quantum_ms(pf_fd, vf_num, 0);
> + igt_warn_on(ret_eq);
> + if (!ret)
> + ret = ret_eq;
> +
> + ret_pt = __xe_sriov_admin_set_preempt_timeout_us(pf_fd, vf_num, 0);
> + igt_warn_on(ret_pt);
> + if (!ret)
> + ret = ret_pt;
> +
> + ret_prio = __xe_sriov_admin_set_sched_priority(pf_fd, vf_num,
> + XE_SRIOV_SCHED_PRIORITY_LOW);
> + igt_warn_on(ret_prio);
> + if (!ret)
> + ret = ret_prio;
> +
> + return ret;
> +}
> +
> +/**
> + * xe_sriov_admin_restore_defaults - Assert wrapper restoring VF defaults
> + * @pf_fd: PF device file descriptor.
> + * @vf_num: VF index (0 for PF, >0 for VFs).
> + */
> +void xe_sriov_admin_restore_defaults(int pf_fd, unsigned int vf_num)
> +{
> + igt_assert_eq(0, __xe_sriov_admin_restore_defaults(pf_fd, vf_num));
> +}
> +
> +/**
> + * __xe_sriov_admin_bulk_restore_defaults - Restore scheduling defaults for PF and all VFs
> + * @pf_fd: PF device file descriptor.
> + *
> + * Resets PF and all VFs to driver default scheduling parameters.
> + *
> + * Returns: 0 on success or negative errno on error.
> + */
> +int __xe_sriov_admin_bulk_restore_defaults(int pf_fd)
> +{
> + int ret_eq, ret_pt, ret_prio;
> + int ret = 0;
> +
> + ret_eq = __xe_sriov_admin_bulk_set_exec_quantum_ms(pf_fd, 0);
> + igt_warn_on(ret_eq);
> + if (!ret)
> + ret = ret_eq;
> +
> + ret_pt = __xe_sriov_admin_bulk_set_preempt_timeout_us(pf_fd, 0);
> + igt_warn_on(ret_pt);
> + if (!ret)
> + ret = ret_pt;
> +
> + ret_prio = __xe_sriov_admin_bulk_set_sched_priority(pf_fd,
> + XE_SRIOV_SCHED_PRIORITY_LOW);
> + igt_warn_on(ret_prio);
> + if (!ret)
> + ret = ret_prio;
> +
> + return ret;
> +}
> +
> +/**
> + * xe_sriov_admin_bulk_restore_defaults - Assert wrapper for restoring defaults on PF and all VFs
> + * @pf_fd: PF device file descriptor.
> + */
> +void xe_sriov_admin_bulk_restore_defaults(int pf_fd)
> +{
> + igt_assert_eq(0, __xe_sriov_admin_bulk_restore_defaults(pf_fd));
> +}
> diff --git a/lib/xe/xe_sriov_admin.h b/lib/xe/xe_sriov_admin.h
> new file mode 100644
> index 000000000..607e33a86
> --- /dev/null
> +++ b/lib/xe/xe_sriov_admin.h
> @@ -0,0 +1,60 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright(c) 2025 Intel Corporation. All rights reserved.
> + */
> +
> +#ifndef __XE_SRIOV_ADMIN_H__
> +#define __XE_SRIOV_ADMIN_H__
> +
> +#include <stdbool.h>
> +#include <stdint.h>
> +#include <stddef.h>
> +#include "xe_sriov_provisioning.h" /* for enum xe_sriov_sched_priority */
> +
> +struct igt_sysfs_choice;
> +
> +bool xe_sriov_admin_is_present(int pf_fd);
> +
> +int __xe_sriov_admin_set_exec_quantum_ms(int pf_fd, unsigned int vf_num, uint32_t eq_ms);
> +void xe_sriov_admin_set_exec_quantum_ms(int pf_fd, unsigned int vf_num, uint32_t eq_ms);
> +int __xe_sriov_admin_get_exec_quantum_ms(int pf_fd, unsigned int vf_num, uint32_t *eq_ms);
> +uint32_t xe_sriov_admin_get_exec_quantum_ms(int pf_fd, unsigned int vf_num);
> +int __xe_sriov_admin_set_preempt_timeout_us(int pf_fd, unsigned int vf_num, uint32_t pt_us);
> +void xe_sriov_admin_set_preempt_timeout_us(int pf_fd, unsigned int vf_num, uint32_t pt_us);
> +int __xe_sriov_admin_get_preempt_timeout_us(int pf_fd, unsigned int vf_num, uint32_t *pt_us);
> +uint32_t xe_sriov_admin_get_preempt_timeout_us(int pf_fd, unsigned int vf_num);
> +int __xe_sriov_admin_set_sched_priority_string(int pf_fd, unsigned int vf_num,
> + const char *prio);
> +int __xe_sriov_admin_get_sched_priority_choice(int pf_fd, unsigned int vf_num,
> + struct igt_sysfs_choice *choice);
> +int __xe_sriov_admin_set_sched_priority(int pf_fd, unsigned int vf_num,
> + enum xe_sriov_sched_priority prio);
> +void xe_sriov_admin_set_sched_priority(int pf_fd, unsigned int vf_num,
> + enum xe_sriov_sched_priority prio);
> +int __xe_sriov_admin_get_sched_priority(int pf_fd, unsigned int vf_num,
> + enum xe_sriov_sched_priority *prio,
> + unsigned int *prio_mask);
> +enum xe_sriov_sched_priority
> +xe_sriov_admin_get_sched_priority(int pf_fd, unsigned int vf_num,
> + unsigned int *prio_mask);
> +
> +int __xe_sriov_admin_bulk_set_exec_quantum_ms(int pf_fd, uint32_t eq_ms);
> +void xe_sriov_admin_bulk_set_exec_quantum_ms(int pf_fd, uint32_t eq_ms);
> +int __xe_sriov_admin_bulk_set_preempt_timeout_us(int pf_fd, uint32_t pt_us);
> +void xe_sriov_admin_bulk_set_preempt_timeout_us(int pf_fd, uint32_t pt_us);
> +int __xe_sriov_admin_bulk_set_sched_priority_string(int pf_fd, const char *prio);
> +void xe_sriov_admin_bulk_set_sched_priority_string(int pf_fd, const char *prio);
> +int __xe_sriov_admin_bulk_set_sched_priority(int pf_fd,
> + enum xe_sriov_sched_priority prio);
> +void xe_sriov_admin_bulk_set_sched_priority(int pf_fd,
> + enum xe_sriov_sched_priority prio);
> +
> +int __xe_sriov_admin_vf_stop(int pf_fd, unsigned int vf_num);
> +void xe_sriov_admin_vf_stop(int pf_fd, unsigned int vf_num);
> +
> +int __xe_sriov_admin_restore_defaults(int pf_fd, unsigned int vf_num);
> +void xe_sriov_admin_restore_defaults(int pf_fd, unsigned int vf_num);
> +int __xe_sriov_admin_bulk_restore_defaults(int pf_fd);
> +void xe_sriov_admin_bulk_restore_defaults(int pf_fd);
> +
> +#endif /* __XE_SRIOV_ADMIN_H__ */
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 i-g-t 07/10] tests/intel/xe_sriov_scheduling: Avoid assert on scheduling params restore in cleanup
2026-01-28 18:08 [PATCH v3 i-g-t 00/10] Xe SR-IOV admin scheduling helpers and test updates Marcin Bernatowicz
` (5 preceding siblings ...)
2026-01-28 18:08 ` [PATCH v3 i-g-t 06/10] lib/xe/xe_sriov_admin: Add SR-IOV admin sysfs accessors Marcin Bernatowicz
@ 2026-01-28 18:08 ` Marcin Bernatowicz
2026-01-28 18:08 ` [PATCH v3 i-g-t 08/10] tests/intel/xe_sriov_scheduling: Prefer SR-IOV admin sysfs accessors Marcin Bernatowicz
` (4 subsequent siblings)
11 siblings, 0 replies; 19+ messages in thread
From: Marcin Bernatowicz @ 2026-01-28 18:08 UTC (permalink / raw)
To: igt-dev
Cc: adam.miszczak, jakub1.kolakowski, lukasz.laguna, michal.wajdeczko,
Marcin Bernatowicz
Add __set_vfs_scheduling_params() that returns error instead of asserting.
Use the non-asserting helper in cleanup paths to ensure VFs are properly
disabled before aborting.
Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
Reviewed-by: Lukasz Laguna <lukasz.laguna@intel.com>
Cc: Adam Miszczak <adam.miszczak@linux.intel.com>
Cc: Jakub Kolakowski <jakub1.kolakowski@intel.com>
Cc: Lukasz Laguna <lukasz.laguna@intel.com>
---
tests/intel/xe_sriov_scheduling.c | 41 ++++++++++++++++++++++++-------
1 file changed, 32 insertions(+), 9 deletions(-)
diff --git a/tests/intel/xe_sriov_scheduling.c b/tests/intel/xe_sriov_scheduling.c
index fad3cbb04..117737d5f 100644
--- a/tests/intel/xe_sriov_scheduling.c
+++ b/tests/intel/xe_sriov_scheduling.c
@@ -371,17 +371,36 @@ struct vf_sched_params {
uint32_t preempt_timeout_us;
};
-static void set_vfs_scheduling_params(int pf_fd, int num_vfs,
- const struct vf_sched_params *p)
+static int __set_vfs_scheduling_params(int pf_fd, int num_vfs,
+ const struct vf_sched_params *p)
{
unsigned int gt;
+ int vf, ret;
xe_for_each_gt(pf_fd, gt) {
- for (int vf = 0; vf <= num_vfs; ++vf) {
- xe_sriov_set_exec_quantum_ms(pf_fd, vf, gt, p->exec_quantum_ms);
- xe_sriov_set_preempt_timeout_us(pf_fd, vf, gt, p->preempt_timeout_us);
+ for (vf = 0; vf <= num_vfs; ++vf) {
+ ret = __xe_sriov_set_exec_quantum_ms(pf_fd, vf, gt,
+ p->exec_quantum_ms);
+ if (igt_warn_on_f(ret,
+ "Failed to set exec_quantum_ms=%u (VF%d GT%u): %d\n",
+ p->exec_quantum_ms, vf, gt, ret))
+ return ret;
+
+ ret = __xe_sriov_set_preempt_timeout_us(pf_fd, vf, gt,
+ p->preempt_timeout_us);
+ if (igt_warn_on_f(ret,
+ "Failed to set preempt_timeout_us=%u (VF%d GT%u): %d\n",
+ p->preempt_timeout_us, vf, gt, ret))
+ return ret;
}
}
+ return 0;
+}
+
+static void set_vfs_scheduling_params(int pf_fd, int num_vfs,
+ const struct vf_sched_params *p)
+{
+ igt_assert_eq(0, __set_vfs_scheduling_params(pf_fd, num_vfs, p));
}
static bool check_within_epsilon(const double x, const double ref, const double tol)
@@ -729,7 +748,7 @@ static void throughput_ratio(int pf_fd, int num_vfs, const struct subm_opts *opt
/* cleanup */
subm_set_fini(set);
- set_vfs_scheduling_params(pf_fd, num_vfs, &(struct vf_sched_params){});
+ __set_vfs_scheduling_params(pf_fd, num_vfs, &(struct vf_sched_params){});
xe_sriov_disable_vfs_restore_auto_provisioning(pf_fd);
}
@@ -815,7 +834,7 @@ static void nonpreempt_engine_resets(int pf_fd, int num_vfs,
/* cleanup */
subm_set_fini(set);
- set_vfs_scheduling_params(pf_fd, num_vfs, &(struct vf_sched_params){});
+ __set_vfs_scheduling_params(pf_fd, num_vfs, &(struct vf_sched_params){});
xe_sriov_disable_vfs_restore_auto_provisioning(pf_fd);
}
@@ -923,8 +942,10 @@ int igt_main_args("", long_opts, help_str, subm_opts_handler, NULL)
}
igt_fixture() {
- set_vfs_scheduling_params(pf_fd, igt_sriov_get_total_vfs(pf_fd),
- &(struct vf_sched_params){});
+ int ret;
+
+ ret = __set_vfs_scheduling_params(pf_fd, igt_sriov_get_total_vfs(pf_fd),
+ &(struct vf_sched_params){});
xe_sriov_disable_vfs_restore_auto_provisioning(pf_fd);
/* abort to avoid execution of next tests with enabled VFs */
igt_abort_on_f(igt_sriov_get_enabled_vfs(pf_fd) > 0,
@@ -933,6 +954,8 @@ int igt_main_args("", long_opts, help_str, subm_opts_handler, NULL)
igt_sriov_disable_driver_autoprobe(pf_fd);
igt_abort_on_f(autoprobe != igt_sriov_is_driver_autoprobe_enabled(pf_fd),
"Failed to restore sriov_drivers_autoprobe value\n");
+ igt_abort_on_f(ret,
+ "Failed to restore scheduling params\n");
drm_close_driver(pf_fd);
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH v3 i-g-t 08/10] tests/intel/xe_sriov_scheduling: Prefer SR-IOV admin sysfs accessors
2026-01-28 18:08 [PATCH v3 i-g-t 00/10] Xe SR-IOV admin scheduling helpers and test updates Marcin Bernatowicz
` (6 preceding siblings ...)
2026-01-28 18:08 ` [PATCH v3 i-g-t 07/10] tests/intel/xe_sriov_scheduling: Avoid assert on scheduling params restore in cleanup Marcin Bernatowicz
@ 2026-01-28 18:08 ` Marcin Bernatowicz
2026-01-28 18:08 ` [PATCH v3 i-g-t 09/10] tests/intel/xe_pmu: " Marcin Bernatowicz
` (3 subsequent siblings)
11 siblings, 0 replies; 19+ messages in thread
From: Marcin Bernatowicz @ 2026-01-28 18:08 UTC (permalink / raw)
To: igt-dev
Cc: adam.miszczak, jakub1.kolakowski, lukasz.laguna, michal.wajdeczko,
Marcin Bernatowicz
Use SR-IOV admin sysfs setters for scheduling parameters,
skip if sriov_admin sysfs not available.
Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
Reviewed-by: Lukasz Laguna <lukasz.laguna@intel.com>
Cc: Adam Miszczak <adam.miszczak@linux.intel.com>
Cc: Jakub Kolakowski <jakub1.kolakowski@intel.com>
Cc: Lukasz Laguna <lukasz.laguna@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
---
v2:
- Adjust to renamed __xe_sriov_admin_* helpers
Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
---
tests/intel/xe_sriov_scheduling.c | 38 ++++++++++++++-----------------
1 file changed, 17 insertions(+), 21 deletions(-)
diff --git a/tests/intel/xe_sriov_scheduling.c b/tests/intel/xe_sriov_scheduling.c
index 117737d5f..4228eea2d 100644
--- a/tests/intel/xe_sriov_scheduling.c
+++ b/tests/intel/xe_sriov_scheduling.c
@@ -9,6 +9,7 @@
#include "xe_drm.h"
#include "xe/xe_ioctl.h"
#include "xe/xe_spin.h"
+#include "xe/xe_sriov_admin.h"
#include "xe/xe_sriov_provisioning.h"
/**
@@ -374,27 +375,21 @@ struct vf_sched_params {
static int __set_vfs_scheduling_params(int pf_fd, int num_vfs,
const struct vf_sched_params *p)
{
- unsigned int gt;
- int vf, ret;
-
- xe_for_each_gt(pf_fd, gt) {
- for (vf = 0; vf <= num_vfs; ++vf) {
- ret = __xe_sriov_set_exec_quantum_ms(pf_fd, vf, gt,
- p->exec_quantum_ms);
- if (igt_warn_on_f(ret,
- "Failed to set exec_quantum_ms=%u (VF%d GT%u): %d\n",
- p->exec_quantum_ms, vf, gt, ret))
- return ret;
-
- ret = __xe_sriov_set_preempt_timeout_us(pf_fd, vf, gt,
- p->preempt_timeout_us);
- if (igt_warn_on_f(ret,
- "Failed to set preempt_timeout_us=%u (VF%d GT%u): %d\n",
- p->preempt_timeout_us, vf, gt, ret))
- return ret;
- }
- }
- return 0;
+ int ret = 0;
+
+ ret = __xe_sriov_admin_bulk_set_exec_quantum_ms(pf_fd, p->exec_quantum_ms);
+ if (igt_warn_on_f(ret,
+ "Failed to bulk set exec quantum=%u: %d\n",
+ p->exec_quantum_ms, ret))
+ return ret;
+
+ ret = __xe_sriov_admin_bulk_set_preempt_timeout_us(pf_fd, p->preempt_timeout_us);
+ if (igt_warn_on_f(ret,
+ "Failed to bulk set preempt timeout=%u: %d\n",
+ p->preempt_timeout_us, ret))
+ return ret;
+
+ return ret;
}
static void set_vfs_scheduling_params(int pf_fd, int num_vfs,
@@ -912,6 +907,7 @@ int igt_main_args("", long_opts, help_str, subm_opts_handler, NULL)
pf_fd = drm_open_driver(DRIVER_XE);
igt_require(igt_sriov_is_pf(pf_fd));
igt_require(igt_sriov_get_enabled_vfs(pf_fd) == 0);
+ igt_require(xe_sriov_admin_is_present(pf_fd));
autoprobe = igt_sriov_is_driver_autoprobe_enabled(pf_fd);
xe_sriov_require_default_scheduling_attributes(pf_fd);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH v3 i-g-t 09/10] tests/intel/xe_pmu: Prefer SR-IOV admin sysfs accessors
2026-01-28 18:08 [PATCH v3 i-g-t 00/10] Xe SR-IOV admin scheduling helpers and test updates Marcin Bernatowicz
` (7 preceding siblings ...)
2026-01-28 18:08 ` [PATCH v3 i-g-t 08/10] tests/intel/xe_sriov_scheduling: Prefer SR-IOV admin sysfs accessors Marcin Bernatowicz
@ 2026-01-28 18:08 ` Marcin Bernatowicz
2026-01-28 18:08 ` [PATCH v3 i-g-t 10/10] tests/intel/xe_sriov_admin: Add SR-IOV admin sysfs scheduling attributes tests Marcin Bernatowicz
` (2 subsequent siblings)
11 siblings, 0 replies; 19+ messages in thread
From: Marcin Bernatowicz @ 2026-01-28 18:08 UTC (permalink / raw)
To: igt-dev
Cc: adam.miszczak, jakub1.kolakowski, lukasz.laguna, michal.wajdeczko,
Marcin Bernatowicz, Jonathan Cavitt, Kamil Konieczny
Switch xe_pmu scheduling configuration to the SR-IOV admin sysfs
setters for exec_quantum_ms, preempt_timeout_us and sched_priority,
skipping the test if sriov_admin is not available.
Also adopts the “Tie preempt timeout to exec quantum” change using the
new sriov_admin interface.
Link: https://lore.kernel.org/igt-dev/20251107151251.6323-2-jonathan.cavitt@intel.com/
Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
Reviewed-by: Lukasz Laguna <lukasz.laguna@intel.com>
Cc: Adam Miszczak <adam.miszczak@linux.intel.com>
Cc: Jakub Kolakowski <jakub1.kolakowski@intel.com>
Cc: Jonathan Cavitt <jonathan.cavitt@intel.com>
Cc: Kamil Konieczny <kamil.konieczny@linux.intel.com>
Cc: Lukasz Laguna <lukasz.laguna@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
---
v2:
- Adjust to renamed __xe_sriov_admin_* helpers
Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
---
tests/intel/xe_pmu.c | 43 ++++++++++++++++++++++---------------------
1 file changed, 22 insertions(+), 21 deletions(-)
diff --git a/tests/intel/xe_pmu.c b/tests/intel/xe_pmu.c
index 33852270a..fb4b871e7 100644
--- a/tests/intel/xe_pmu.c
+++ b/tests/intel/xe_pmu.c
@@ -102,6 +102,7 @@
#include "xe/xe_gt.h"
#include "xe/xe_ioctl.h"
#include "xe/xe_spin.h"
+#include "xe/xe_sriov_admin.h"
#include "xe/xe_sriov_provisioning.h"
#define SLEEP_DURATION 2 /* in seconds */
@@ -702,7 +703,7 @@ static void engine_activity_all_fn(int fd, struct drm_xe_engine_class_instance *
}
static void engine_activity_fn(int fd, struct drm_xe_engine_class_instance *eci,
- int function, bool sched_if_idle)
+ int function, enum xe_sriov_sched_priority prio)
{
uint64_t config, engine_active_ticks, engine_total_ticks, before[2], after[2];
double busy_percent, exec_quantum_ratio;
@@ -710,6 +711,9 @@ static void engine_activity_fn(int fd, struct drm_xe_engine_class_instance *eci,
int pmu_fd[2], fn_fd;
uint32_t vm;
+ if (prio != xe_sriov_admin_get_sched_priority(fd, 0, NULL))
+ xe_sriov_admin_bulk_set_sched_priority(fd, prio);
+
if (function > 0) {
fn_fd = igt_sriov_open_vf_drm_device(fd, function);
igt_assert_fd(fn_fd);
@@ -757,7 +761,7 @@ static void engine_activity_fn(int fd, struct drm_xe_engine_class_instance *eci,
if (function > 0)
close(fn_fd);
- if (sched_if_idle)
+ if (prio == XE_SRIOV_SCHED_PRIORITY_NORMAL)
assert_within_epsilon(engine_active_ticks, engine_total_ticks, tolerance);
else
assert_within_epsilon(busy_percent, exec_quantum_ratio, tolerance);
@@ -982,10 +986,12 @@ static void test_gt_frequency(int fd, struct drm_xe_engine_class_instance *eci)
static unsigned int enable_and_provision_vfs(int fd)
{
- unsigned int gt, num_vfs;
- int pf_exec_quantum = 64, vf_exec_quantum = 32, vf;
+ unsigned int num_vfs, vf;
+ uint32_t pf_exec_quantum_ms = 64, vf_exec_quantum_ms = 32;
+ uint32_t pf_preempt_timeout_us = 64000, vf_preempt_timeout_us = 32000;
igt_require(igt_sriov_is_pf(fd));
+ igt_require(xe_sriov_admin_is_present(fd));
igt_require(igt_sriov_get_enabled_vfs(fd) == 0);
xe_sriov_require_default_scheduling_attributes(fd);
autoprobe = igt_sriov_is_driver_autoprobe_enabled(fd);
@@ -997,37 +1003,33 @@ static unsigned int enable_and_provision_vfs(int fd)
igt_require(num_vfs == 2);
/* Set 32ms for VF execution quantum and 64ms for PF execution quantum */
- xe_for_each_gt(fd, gt) {
- xe_sriov_set_sched_if_idle(fd, gt, 0);
- for (int fn = 0; fn <= num_vfs; fn++)
- xe_sriov_set_exec_quantum_ms(fd, fn, gt, fn ? vf_exec_quantum :
- pf_exec_quantum);
- }
+ xe_sriov_admin_bulk_set_exec_quantum_ms(fd, vf_exec_quantum_ms);
+ xe_sriov_admin_bulk_set_preempt_timeout_us(fd, vf_preempt_timeout_us);
+ xe_sriov_admin_bulk_set_sched_priority(fd, XE_SRIOV_SCHED_PRIORITY_LOW);
+ xe_sriov_admin_set_exec_quantum_ms(fd, 0, pf_exec_quantum_ms);
+ xe_sriov_admin_set_preempt_timeout_us(fd, 0,
+ pf_preempt_timeout_us);
/* probe VFs */
igt_sriov_enable_driver_autoprobe(fd);
for (vf = 1; vf <= num_vfs; vf++)
igt_sriov_bind_vf_drm_driver(fd, vf);
- total_exec_quantum = pf_exec_quantum + (num_vfs * vf_exec_quantum);
+ total_exec_quantum = pf_exec_quantum_ms + (num_vfs * vf_exec_quantum_ms);
return num_vfs;
}
static void unprovision_and_disable_vfs(int fd)
{
- unsigned int gt, num_vfs = igt_sriov_get_enabled_vfs(fd);
-
- xe_for_each_gt(fd, gt) {
- xe_sriov_set_sched_if_idle(fd, gt, 0);
- for (int fn = 0; fn <= num_vfs; fn++)
- xe_sriov_set_exec_quantum_ms(fd, fn, gt, 0);
- }
+ int ret;
+ ret = __xe_sriov_admin_bulk_restore_defaults(fd);
xe_sriov_disable_vfs_restore_auto_provisioning(fd);
/* abort to avoid execution of next tests with enabled VFs */
igt_abort_on_f(igt_sriov_get_enabled_vfs(fd) > 0,
"Failed to disable VF(s)");
+ igt_abort_on_f(ret, "Failed to restore scheduling params\n");
autoprobe ? igt_sriov_enable_driver_autoprobe(fd) :
igt_sriov_disable_driver_autoprobe(fd);
@@ -1197,13 +1199,12 @@ int igt_main()
igt_describe("Validate per-function engine activity");
test_each_engine("fn-engine-activity-load", fd, eci)
for (int fn = 0; fn < num_fns; fn++)
- engine_activity_fn(fd, eci, fn, false);
+ engine_activity_fn(fd, eci, fn, XE_SRIOV_SCHED_PRIORITY_LOW);
igt_describe("Validate per-function engine activity when sched-if-idle is set");
test_each_engine("fn-engine-activity-sched-if-idle", fd, eci) {
- xe_sriov_set_sched_if_idle(fd, eci->gt_id, 1);
for (int fn = 0; fn < num_fns; fn++)
- engine_activity_fn(fd, eci, fn, true);
+ engine_activity_fn(fd, eci, fn, XE_SRIOV_SCHED_PRIORITY_NORMAL);
}
igt_fixture()
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH v3 i-g-t 10/10] tests/intel/xe_sriov_admin: Add SR-IOV admin sysfs scheduling attributes tests
2026-01-28 18:08 [PATCH v3 i-g-t 00/10] Xe SR-IOV admin scheduling helpers and test updates Marcin Bernatowicz
` (8 preceding siblings ...)
2026-01-28 18:08 ` [PATCH v3 i-g-t 09/10] tests/intel/xe_pmu: " Marcin Bernatowicz
@ 2026-01-28 18:08 ` Marcin Bernatowicz
2026-01-29 8:21 ` Laguna, Lukasz
2026-01-28 20:32 ` ✓ Xe.CI.BAT: success for Xe SR-IOV admin scheduling helpers and test updates (rev3) Patchwork
2026-01-28 20:47 ` ✗ i915.CI.BAT: failure " Patchwork
11 siblings, 1 reply; 19+ messages in thread
From: Marcin Bernatowicz @ 2026-01-28 18:08 UTC (permalink / raw)
To: igt-dev
Cc: adam.miszczak, jakub1.kolakowski, lukasz.laguna, michal.wajdeczko,
Marcin Bernatowicz, Kamil Konieczny
Add tests that exercise SR-IOV admin sysfs attributes for PF/VF functions
with VFs disabled, covering default values, write -> readback behavior, and
bulk updates for exec_quantum_ms, preempt_timeout_us, and sched_priority.
Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
Cc: Adam Miszczak <adam.miszczak@linux.intel.com>
Cc: Jakub Kolakowski <jakub1.kolakowski@intel.com>
Cc: Kamil Konieczny <kamil.konieczny@linux.intel.com>
Cc: Lukasz Laguna <lukasz.laguna@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
---
v2:
- Align igt_main()/igt_fixture() usage with upstream changes.
- Correct date
- Replace id with vf_id
- Iterate all VF sched_priority tokens and verify denied
writes don’t change selection. (Lukasz)
- Rename xe_sriov_admin_profile to xe_sriov_admin (Lukasz)
- Adjust test for xe_sriov_sched_priority_mask_to_string() returning
error code.
- Adjust to renamed __xe_sriov_admin_* helpers
Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
---
tests/intel/xe_sriov_admin.c | 434 +++++++++++++++++++++++++++++++++++
tests/meson.build | 1 +
2 files changed, 435 insertions(+)
create mode 100644 tests/intel/xe_sriov_admin.c
diff --git a/tests/intel/xe_sriov_admin.c b/tests/intel/xe_sriov_admin.c
new file mode 100644
index 000000000..5c7f5d621
--- /dev/null
+++ b/tests/intel/xe_sriov_admin.c
@@ -0,0 +1,434 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+#include "igt.h"
+#include "igt_sriov_device.h"
+#include "igt_sysfs.h"
+#include "igt_sysfs_choice.h"
+#include "xe_drm.h"
+#include "xe/xe_sriov_admin.h"
+
+/**
+ * TEST: Tests for SR-IOV admin sysfs.
+ * Category: Core
+ * Mega feature: SR-IOV
+ * Sub-category: sysfs
+ * Functionality: SR-IOV admin sysfs
+ * Description: Verify behavior of exposed SR-IOV admin sysfs attributes.
+ */
+
+/**
+ * SUBTEST: default-sched-attributes-vfs-disabled
+ * Description:
+ * Verify default scheduling attributes under sriov_admin
+ * with VFs disabled.
+ */
+static void default_sched_attributes(int pf_fd, int vf_num)
+{
+ igt_dynamic_f("%s-default-exec-quantum", igt_sriov_func_str(vf_num)) {
+ igt_assert_eq(0, xe_sriov_admin_get_exec_quantum_ms(pf_fd, vf_num));
+ }
+
+ igt_dynamic_f("%s-default-preempt-timeout", igt_sriov_func_str(vf_num)) {
+ igt_assert_eq(0, xe_sriov_admin_get_preempt_timeout_us(pf_fd, vf_num));
+ }
+
+ igt_dynamic_f("%s-default-sched-priority", igt_sriov_func_str(vf_num)) {
+ enum xe_sriov_sched_priority prio;
+ unsigned int prio_mask;
+ char mask_str[64];
+ int ret;
+
+ prio = xe_sriov_admin_get_sched_priority(pf_fd, vf_num, &prio_mask);
+ ret = xe_sriov_sched_priority_mask_to_string(mask_str, sizeof(mask_str),
+ prio_mask, prio);
+ igt_debug("sched_priority: ret=%d mask=0x%x selected_idx=%d str='%s'\n",
+ ret, prio_mask, prio, mask_str);
+ igt_assert_eq(ret, 0);
+ igt_assert_eq(XE_SRIOV_SCHED_PRIORITY_LOW, prio);
+ }
+}
+
+/**
+ * SUBTEST: exec-quantum-write-readback-vfs-disabled
+ * Description:
+ * Verify write -> readback of exec_quantum_ms under sriov_admin
+ * for PF and all VFs with VFs disabled.
+ */
+static void exec_quantum_write_readback(int pf_fd, unsigned int vf_num,
+ uint32_t eq_ms)
+{
+ int ret_read, ret_restore;
+ uint32_t read_val;
+
+ igt_require(xe_sriov_admin_get_exec_quantum_ms(pf_fd, vf_num) == 0);
+
+ xe_sriov_admin_set_exec_quantum_ms(pf_fd, vf_num, eq_ms);
+
+ ret_read = __xe_sriov_admin_get_exec_quantum_ms(pf_fd, vf_num, &read_val);
+
+ ret_restore = __xe_sriov_admin_set_exec_quantum_ms(pf_fd, vf_num, 0);
+
+ igt_assert_eq(ret_read, 0);
+ igt_assert_eq(read_val, eq_ms);
+ igt_fail_on(ret_restore);
+}
+
+/**
+ * SUBTEST: preempt-timeout-write-readback-vfs-disabled
+ * Description:
+ * Verify write -> readback of preempt_timeout_us under sriov_admin
+ * for PF and all VFs with VFs disabled.
+ */
+static void preempt_timeout_write_readback(int pf_fd, unsigned int vf_num,
+ uint32_t pt_us)
+{
+ int ret_read, ret_restore;
+ uint32_t read_val;
+
+ igt_require(xe_sriov_admin_get_preempt_timeout_us(pf_fd, vf_num) == 0);
+
+ xe_sriov_admin_set_preempt_timeout_us(pf_fd, vf_num, pt_us);
+
+ ret_read = __xe_sriov_admin_get_preempt_timeout_us(pf_fd, vf_num, &read_val);
+
+ ret_restore = __xe_sriov_admin_set_preempt_timeout_us(pf_fd, vf_num, 0);
+
+ igt_assert_eq(ret_read, 0);
+ igt_assert_eq(read_val, pt_us);
+ igt_fail_on(ret_restore);
+}
+
+/**
+ * SUBTEST: sched-priority-write-readback-vfs-disabled
+ * Description:
+ * Verify write -> readback of sched_priority under sriov_admin
+ * for PF and all VFs with VFs disabled.
+ */
+static void sched_priority_write_readback(int pf_fd, unsigned int vf_num)
+{
+ struct igt_sysfs_choice prio, now;
+ enum xe_sriov_sched_priority prio_enum;
+ int ret;
+
+ ret = __xe_sriov_admin_get_sched_priority_choice(pf_fd, vf_num, &prio);
+ igt_assert_eq(ret, 0);
+
+ for (size_t n = prio.num_tokens; n-- > 0; ) {
+ igt_warn_on_f(xe_sriov_sched_priority_from_string(prio.tokens[n],
+ &prio_enum),
+ "Unrecognized sched_priority value '%s'\n",
+ prio.tokens[n]);
+ igt_debug("Setting priority string '%s'\n", prio.tokens[n]);
+ ret = __xe_sriov_admin_set_sched_priority_string(pf_fd, vf_num,
+ prio.tokens[n]);
+
+ /* Not settable on VF */
+ if (igt_debug_on(vf_num && (ret == -EPERM || ret == -EACCES)))
+ break;
+
+ igt_assert_eq(ret, 0);
+ ret = __xe_sriov_admin_get_sched_priority_choice(pf_fd, vf_num, &now);
+ igt_assert_f(!strcmp(now.tokens[now.selected], prio.tokens[n]),
+ "'%s' != '%s'", now.tokens[now.selected],
+ prio.tokens[n]);
+ igt_assert_eq(now.selected, n);
+ }
+ __xe_sriov_admin_set_sched_priority_string(pf_fd, vf_num,
+ prio.tokens[prio.selected]);
+}
+
+/**
+ * SUBTEST: bulk-exec-quantum-vfs-disabled
+ * Description:
+ * Verify that bulk setting exec_quantum_ms under sriov_admin applies
+ * the expected value to the PF and all VFs when VFs are disabled.
+ */
+static void bulk_set_exec_quantum(int pf_fd, unsigned int total_vfs, uint32_t eq_ms)
+{
+ uint32_t read_val;
+ unsigned int vf_id;
+ int fails = 0;
+
+ xe_sriov_admin_bulk_set_exec_quantum_ms(pf_fd, eq_ms);
+
+ for (vf_id = 0; vf_id <= total_vfs; ++vf_id) {
+ int ret = __xe_sriov_admin_get_exec_quantum_ms(pf_fd, vf_id,
+ &read_val);
+
+ if (ret) {
+ igt_debug("%s: failed to read exec_quantum_ms, ret=%d\n",
+ igt_sriov_func_str(vf_id), ret);
+ fails++;
+ continue;
+ }
+
+ if (read_val != eq_ms) {
+ igt_debug("%s: exec_quantum_ms=%u, expected=%u\n",
+ igt_sriov_func_str(vf_id), read_val, eq_ms);
+ fails++;
+ }
+ }
+
+ xe_sriov_admin_bulk_set_exec_quantum_ms(pf_fd, 0);
+ igt_fail_on(fails);
+}
+
+/**
+ * SUBTEST: bulk-preempt-timeout-vfs-disabled
+ * Description:
+ * Verify that bulk setting preempt_timeout_us under sriov_admin applies
+ * the expected value to the PF and all VFs when VFs are disabled.
+ */
+static void bulk_set_preempt_timeout(int pf_fd, unsigned int total_vfs, uint32_t pt_us)
+{
+ uint32_t read_val;
+ unsigned int id;
+ int fails = 0;
+
+ xe_sriov_admin_bulk_set_preempt_timeout_us(pf_fd, pt_us);
+
+ for (id = 0; id <= total_vfs; ++id) {
+ int ret = __xe_sriov_admin_get_preempt_timeout_us(pf_fd, id,
+ &read_val);
+
+ if (ret) {
+ igt_debug("%s: failed to read preempt_timeout_us, ret=%d\n",
+ igt_sriov_func_str(id), ret);
+ fails++;
+ continue;
+ }
+
+ if (read_val != pt_us) {
+ igt_debug("%s: preempt_timeout_us=%u, expected=%u\n",
+ igt_sriov_func_str(id), read_val, pt_us);
+ fails++;
+ }
+ }
+
+ xe_sriov_admin_bulk_set_preempt_timeout_us(pf_fd, 0);
+ igt_fail_on(fails);
+}
+
+static void build_common_sched_priority_choice(int pf_fd, int num_vfs,
+ struct igt_sysfs_choice *common)
+{
+ int ret;
+
+ /* Start from PF */
+ ret = __xe_sriov_admin_get_sched_priority_choice(pf_fd, 0, common);
+ igt_require_f(ret == 0,
+ "Failed to read PF sched_priority (ret=%d)\n", ret);
+
+ igt_require_f(common->num_tokens > 0,
+ "PF sched_priority exposes no tokens\n");
+
+ /* Intersect with every VF 1..num_vfs */
+ for (int vf = 1; vf <= num_vfs; vf++) {
+ struct igt_sysfs_choice prio = {};
+
+ ret = __xe_sriov_admin_get_sched_priority_choice(pf_fd, vf, &prio);
+ igt_require_f(ret == 0,
+ "Failed to read VF%u sched_priority (ret=%d)\n",
+ vf, ret);
+
+ ret = igt_sysfs_choice_intersect(common, &prio);
+ igt_require_f(ret == 0,
+ "No common sched_priority between PF and VF%u\n",
+ vf);
+ }
+
+ igt_require_f(common->num_tokens > 0,
+ "No common sched_priority across PF and all VFs\n");
+
+ if (common->selected < 0) {
+ igt_debug("Common sched_priority has no selected token, "
+ "defaulting to tokens[0]=\"%s\"\n",
+ common->tokens[0]);
+ common->selected = 0;
+ }
+}
+
+/**
+ * SUBTEST: bulk-sched-priority-vfs-disabled
+ * Description: Verify bulk sched_priority modification with VFs disabled.
+ */
+static void bulk_set_sched_priority(int pf_fd, unsigned int total_vfs, const char *prio_str)
+{
+ struct igt_sysfs_choice read_val;
+ const char *selected;
+ unsigned int id;
+ int fails = 0;
+
+ xe_sriov_admin_bulk_set_sched_priority_string(pf_fd, prio_str);
+
+ for (id = 0; id <= total_vfs; ++id) {
+ int ret = __xe_sriov_admin_get_sched_priority_choice(pf_fd, id,
+ &read_val);
+
+ if (ret) {
+ igt_debug("%s: failed to read sched_priority, ret=%d\n",
+ igt_sriov_func_str(id), ret);
+ fails++;
+ continue;
+ }
+
+ selected = igt_sysfs_choice_selected(&read_val);
+ if (!selected || strncmp(selected, prio_str, strlen(prio_str))) {
+ igt_debug("%s: sched_priority='%s', expected='%s'\n",
+ igt_sriov_func_str(id), selected ?: "NULL", prio_str);
+ fails++;
+ }
+ }
+
+ igt_fail_on(fails);
+}
+
+/**
+ * SUBTEST: sched-priority-vf-write-denied
+ * Description:
+ * Verify that sched_priority cannot be modified on a VF.
+ * A write attempt must fail with -EPERM or -EACCES and the
+ * current priority selection must remain unchanged.
+ */
+static void sched_priority_vf_write_denied(int pf_fd, unsigned int vf_num)
+{
+ struct igt_sysfs_choice before, after;
+ const char *new_token;
+ const char *baseline;
+ int baseline_selected;
+ bool attempted = false;
+ int ret;
+
+ igt_require(vf_num > 0);
+
+ ret = __xe_sriov_admin_get_sched_priority_choice(pf_fd, vf_num, &before);
+ igt_require(ret == 0);
+ igt_require(before.num_tokens > 0);
+ igt_require(before.selected >= 0);
+
+ baseline_selected = before.selected;
+ baseline = igt_sysfs_choice_selected(&before);
+ igt_require(baseline);
+
+ for (size_t i = 0; i < before.num_tokens; i++) {
+ if (before.num_tokens > 1 && (int)i == baseline_selected)
+ continue;
+
+ new_token = before.tokens[i];
+ attempted = true;
+
+ ret = __xe_sriov_admin_set_sched_priority_string(pf_fd, vf_num,
+ new_token);
+ igt_assert_f(ret == -EPERM || ret == -EACCES,
+ "Expected -EPERM/-EACCES when writing VF sched_priority "
+ "(token='%s'), got %d\n", new_token, ret);
+
+ ret = __xe_sriov_admin_get_sched_priority_choice(pf_fd, vf_num,
+ &after);
+ igt_assert_eq(ret, 0);
+
+ igt_assert_eq(after.selected, baseline_selected);
+ igt_assert(!strcmp(baseline, igt_sysfs_choice_selected(&after)));
+ }
+
+ igt_assert(attempted);
+}
+
+int igt_main()
+{
+ unsigned int total_vfs;
+ int pf_fd;
+
+ igt_fixture() {
+ pf_fd = drm_open_driver(DRIVER_XE);
+ igt_require(igt_sriov_is_pf(pf_fd));
+ igt_require(igt_sriov_get_enabled_vfs(pf_fd) == 0);
+ igt_require(xe_sriov_admin_is_present(pf_fd));
+ total_vfs = igt_sriov_get_total_vfs(pf_fd);
+ }
+
+ igt_subtest_with_dynamic("default-sched-attributes-vfs-disabled") {
+ for (unsigned int id = 0; id <= total_vfs; ++id)
+ default_sched_attributes(pf_fd, id);
+ }
+
+ igt_subtest_with_dynamic("exec-quantum-write-readback-vfs-disabled") {
+ uint32_t eq_ms = 10;
+
+ for (unsigned int id = 0; id <= total_vfs; ++id) {
+ igt_dynamic_f("%s-eq_ms-%u", igt_sriov_func_str(id), eq_ms) {
+ exec_quantum_write_readback(pf_fd, id, eq_ms);
+ }
+ }
+ }
+
+ igt_subtest_with_dynamic("preempt-timeout-write-readback-vfs-disabled") {
+ uint32_t pt_us = 20000;
+
+ for (unsigned int id = 0; id <= total_vfs; ++id) {
+ igt_dynamic_f("%s-pt_us-%u", igt_sriov_func_str(id), pt_us) {
+ preempt_timeout_write_readback(pf_fd, id, pt_us);
+ }
+ }
+ }
+
+ igt_subtest_with_dynamic("sched-priority-write-readback-vfs-disabled") {
+ for (unsigned int id = 0; id <= total_vfs; ++id) {
+ igt_dynamic_f("%s", igt_sriov_func_str(id)) {
+ sched_priority_write_readback(pf_fd, id);
+ }
+ }
+ }
+
+ igt_subtest_with_dynamic("sched-priority-vf-write-denied") {
+ for_each_sriov_num_vfs(pf_fd, vf_num) {
+ igt_dynamic_f("%s", igt_sriov_func_str(vf_num)) {
+ sched_priority_vf_write_denied(pf_fd, vf_num);
+ }
+ }
+ }
+
+ igt_subtest("bulk-exec-quantum-vfs-disabled") {
+ const uint32_t eq_ms = 10;
+
+ bulk_set_exec_quantum(pf_fd, total_vfs, eq_ms);
+ }
+
+ igt_subtest("bulk-preempt-timeout-vfs-disabled") {
+ uint32_t pt_us = 10000;
+
+ bulk_set_preempt_timeout(pf_fd, total_vfs, pt_us);
+ }
+
+ igt_subtest_group() {
+ struct igt_sysfs_choice prio = {};
+
+ igt_fixture() {
+ build_common_sched_priority_choice(pf_fd, total_vfs,
+ &prio);
+ }
+
+ igt_subtest_with_dynamic_f("bulk-sched-priority-vfs-disabled") {
+ for (size_t i = prio.num_tokens; i-- > 0; ) {
+ const char *prio_str = prio.tokens[i];
+
+ igt_dynamic_f("%s", prio_str)
+ bulk_set_sched_priority(pf_fd, 0, prio_str);
+ }
+ }
+ }
+
+ igt_fixture() {
+ int ret;
+
+ ret = __xe_sriov_admin_bulk_restore_defaults(pf_fd);
+ igt_sriov_disable_vfs(pf_fd);
+ /* abort to avoid execution of next tests with enabled VFs */
+ igt_abort_on_f(igt_sriov_get_enabled_vfs(pf_fd) > 0,
+ "Failed to disable VF(s)");
+ igt_abort_on_f(ret, "Failed to restore default profile values\n");
+ drm_close_driver(pf_fd);
+ }
+}
diff --git a/tests/meson.build b/tests/meson.build
index 0ad728b87..ef4edaa0d 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -331,6 +331,7 @@ intel_xe_progs = [
'xe_vm',
'xe_waitfence',
'xe_spin_batch',
+ 'xe_sriov_admin',
'xe_sriov_auto_provisioning',
'xe_sriov_flr',
'xe_sriov_scheduling',
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* Re: [PATCH v3 i-g-t 10/10] tests/intel/xe_sriov_admin: Add SR-IOV admin sysfs scheduling attributes tests
2026-01-28 18:08 ` [PATCH v3 i-g-t 10/10] tests/intel/xe_sriov_admin: Add SR-IOV admin sysfs scheduling attributes tests Marcin Bernatowicz
@ 2026-01-29 8:21 ` Laguna, Lukasz
0 siblings, 0 replies; 19+ messages in thread
From: Laguna, Lukasz @ 2026-01-29 8:21 UTC (permalink / raw)
To: Marcin Bernatowicz, igt-dev
Cc: adam.miszczak, jakub1.kolakowski, michal.wajdeczko,
Kamil Konieczny
On 1/28/2026 19:08, Marcin Bernatowicz wrote:
> Add tests that exercise SR-IOV admin sysfs attributes for PF/VF functions
> with VFs disabled, covering default values, write -> readback behavior, and
> bulk updates for exec_quantum_ms, preempt_timeout_us, and sched_priority.
>
> Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
> Cc: Adam Miszczak <adam.miszczak@linux.intel.com>
> Cc: Jakub Kolakowski <jakub1.kolakowski@intel.com>
> Cc: Kamil Konieczny <kamil.konieczny@linux.intel.com>
> Cc: Lukasz Laguna <lukasz.laguna@intel.com>
Reviewed-by: Lukasz Laguna <lukasz.laguna@intel.com>
> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
>
> ---
> v2:
> - Align igt_main()/igt_fixture() usage with upstream changes.
> - Correct date
> - Replace id with vf_id
> - Iterate all VF sched_priority tokens and verify denied
> writes don’t change selection. (Lukasz)
> - Rename xe_sriov_admin_profile to xe_sriov_admin (Lukasz)
> - Adjust test for xe_sriov_sched_priority_mask_to_string() returning
> error code.
> - Adjust to renamed __xe_sriov_admin_* helpers
>
> Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
> ---
> tests/intel/xe_sriov_admin.c | 434 +++++++++++++++++++++++++++++++++++
> tests/meson.build | 1 +
> 2 files changed, 435 insertions(+)
> create mode 100644 tests/intel/xe_sriov_admin.c
>
> diff --git a/tests/intel/xe_sriov_admin.c b/tests/intel/xe_sriov_admin.c
> new file mode 100644
> index 000000000..5c7f5d621
> --- /dev/null
> +++ b/tests/intel/xe_sriov_admin.c
> @@ -0,0 +1,434 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2026 Intel Corporation
> + */
> +#include "igt.h"
> +#include "igt_sriov_device.h"
> +#include "igt_sysfs.h"
> +#include "igt_sysfs_choice.h"
> +#include "xe_drm.h"
> +#include "xe/xe_sriov_admin.h"
> +
> +/**
> + * TEST: Tests for SR-IOV admin sysfs.
> + * Category: Core
> + * Mega feature: SR-IOV
> + * Sub-category: sysfs
> + * Functionality: SR-IOV admin sysfs
> + * Description: Verify behavior of exposed SR-IOV admin sysfs attributes.
> + */
> +
> +/**
> + * SUBTEST: default-sched-attributes-vfs-disabled
> + * Description:
> + * Verify default scheduling attributes under sriov_admin
> + * with VFs disabled.
> + */
> +static void default_sched_attributes(int pf_fd, int vf_num)
> +{
> + igt_dynamic_f("%s-default-exec-quantum", igt_sriov_func_str(vf_num)) {
> + igt_assert_eq(0, xe_sriov_admin_get_exec_quantum_ms(pf_fd, vf_num));
> + }
> +
> + igt_dynamic_f("%s-default-preempt-timeout", igt_sriov_func_str(vf_num)) {
> + igt_assert_eq(0, xe_sriov_admin_get_preempt_timeout_us(pf_fd, vf_num));
> + }
> +
> + igt_dynamic_f("%s-default-sched-priority", igt_sriov_func_str(vf_num)) {
> + enum xe_sriov_sched_priority prio;
> + unsigned int prio_mask;
> + char mask_str[64];
> + int ret;
> +
> + prio = xe_sriov_admin_get_sched_priority(pf_fd, vf_num, &prio_mask);
> + ret = xe_sriov_sched_priority_mask_to_string(mask_str, sizeof(mask_str),
> + prio_mask, prio);
> + igt_debug("sched_priority: ret=%d mask=0x%x selected_idx=%d str='%s'\n",
> + ret, prio_mask, prio, mask_str);
> + igt_assert_eq(ret, 0);
> + igt_assert_eq(XE_SRIOV_SCHED_PRIORITY_LOW, prio);
> + }
> +}
> +
> +/**
> + * SUBTEST: exec-quantum-write-readback-vfs-disabled
> + * Description:
> + * Verify write -> readback of exec_quantum_ms under sriov_admin
> + * for PF and all VFs with VFs disabled.
> + */
> +static void exec_quantum_write_readback(int pf_fd, unsigned int vf_num,
> + uint32_t eq_ms)
> +{
> + int ret_read, ret_restore;
> + uint32_t read_val;
> +
> + igt_require(xe_sriov_admin_get_exec_quantum_ms(pf_fd, vf_num) == 0);
> +
> + xe_sriov_admin_set_exec_quantum_ms(pf_fd, vf_num, eq_ms);
> +
> + ret_read = __xe_sriov_admin_get_exec_quantum_ms(pf_fd, vf_num, &read_val);
> +
> + ret_restore = __xe_sriov_admin_set_exec_quantum_ms(pf_fd, vf_num, 0);
> +
> + igt_assert_eq(ret_read, 0);
> + igt_assert_eq(read_val, eq_ms);
> + igt_fail_on(ret_restore);
> +}
> +
> +/**
> + * SUBTEST: preempt-timeout-write-readback-vfs-disabled
> + * Description:
> + * Verify write -> readback of preempt_timeout_us under sriov_admin
> + * for PF and all VFs with VFs disabled.
> + */
> +static void preempt_timeout_write_readback(int pf_fd, unsigned int vf_num,
> + uint32_t pt_us)
> +{
> + int ret_read, ret_restore;
> + uint32_t read_val;
> +
> + igt_require(xe_sriov_admin_get_preempt_timeout_us(pf_fd, vf_num) == 0);
> +
> + xe_sriov_admin_set_preempt_timeout_us(pf_fd, vf_num, pt_us);
> +
> + ret_read = __xe_sriov_admin_get_preempt_timeout_us(pf_fd, vf_num, &read_val);
> +
> + ret_restore = __xe_sriov_admin_set_preempt_timeout_us(pf_fd, vf_num, 0);
> +
> + igt_assert_eq(ret_read, 0);
> + igt_assert_eq(read_val, pt_us);
> + igt_fail_on(ret_restore);
> +}
> +
> +/**
> + * SUBTEST: sched-priority-write-readback-vfs-disabled
> + * Description:
> + * Verify write -> readback of sched_priority under sriov_admin
> + * for PF and all VFs with VFs disabled.
> + */
> +static void sched_priority_write_readback(int pf_fd, unsigned int vf_num)
> +{
> + struct igt_sysfs_choice prio, now;
> + enum xe_sriov_sched_priority prio_enum;
> + int ret;
> +
> + ret = __xe_sriov_admin_get_sched_priority_choice(pf_fd, vf_num, &prio);
> + igt_assert_eq(ret, 0);
> +
> + for (size_t n = prio.num_tokens; n-- > 0; ) {
> + igt_warn_on_f(xe_sriov_sched_priority_from_string(prio.tokens[n],
> + &prio_enum),
> + "Unrecognized sched_priority value '%s'\n",
> + prio.tokens[n]);
> + igt_debug("Setting priority string '%s'\n", prio.tokens[n]);
> + ret = __xe_sriov_admin_set_sched_priority_string(pf_fd, vf_num,
> + prio.tokens[n]);
> +
> + /* Not settable on VF */
> + if (igt_debug_on(vf_num && (ret == -EPERM || ret == -EACCES)))
> + break;
> +
> + igt_assert_eq(ret, 0);
> + ret = __xe_sriov_admin_get_sched_priority_choice(pf_fd, vf_num, &now);
> + igt_assert_f(!strcmp(now.tokens[now.selected], prio.tokens[n]),
> + "'%s' != '%s'", now.tokens[now.selected],
> + prio.tokens[n]);
> + igt_assert_eq(now.selected, n);
> + }
> + __xe_sriov_admin_set_sched_priority_string(pf_fd, vf_num,
> + prio.tokens[prio.selected]);
> +}
> +
> +/**
> + * SUBTEST: bulk-exec-quantum-vfs-disabled
> + * Description:
> + * Verify that bulk setting exec_quantum_ms under sriov_admin applies
> + * the expected value to the PF and all VFs when VFs are disabled.
> + */
> +static void bulk_set_exec_quantum(int pf_fd, unsigned int total_vfs, uint32_t eq_ms)
> +{
> + uint32_t read_val;
> + unsigned int vf_id;
> + int fails = 0;
> +
> + xe_sriov_admin_bulk_set_exec_quantum_ms(pf_fd, eq_ms);
> +
> + for (vf_id = 0; vf_id <= total_vfs; ++vf_id) {
> + int ret = __xe_sriov_admin_get_exec_quantum_ms(pf_fd, vf_id,
> + &read_val);
> +
> + if (ret) {
> + igt_debug("%s: failed to read exec_quantum_ms, ret=%d\n",
> + igt_sriov_func_str(vf_id), ret);
> + fails++;
> + continue;
> + }
> +
> + if (read_val != eq_ms) {
> + igt_debug("%s: exec_quantum_ms=%u, expected=%u\n",
> + igt_sriov_func_str(vf_id), read_val, eq_ms);
> + fails++;
> + }
> + }
> +
> + xe_sriov_admin_bulk_set_exec_quantum_ms(pf_fd, 0);
> + igt_fail_on(fails);
> +}
> +
> +/**
> + * SUBTEST: bulk-preempt-timeout-vfs-disabled
> + * Description:
> + * Verify that bulk setting preempt_timeout_us under sriov_admin applies
> + * the expected value to the PF and all VFs when VFs are disabled.
> + */
> +static void bulk_set_preempt_timeout(int pf_fd, unsigned int total_vfs, uint32_t pt_us)
> +{
> + uint32_t read_val;
> + unsigned int id;
> + int fails = 0;
> +
> + xe_sriov_admin_bulk_set_preempt_timeout_us(pf_fd, pt_us);
> +
> + for (id = 0; id <= total_vfs; ++id) {
> + int ret = __xe_sriov_admin_get_preempt_timeout_us(pf_fd, id,
> + &read_val);
> +
> + if (ret) {
> + igt_debug("%s: failed to read preempt_timeout_us, ret=%d\n",
> + igt_sriov_func_str(id), ret);
> + fails++;
> + continue;
> + }
> +
> + if (read_val != pt_us) {
> + igt_debug("%s: preempt_timeout_us=%u, expected=%u\n",
> + igt_sriov_func_str(id), read_val, pt_us);
> + fails++;
> + }
> + }
> +
> + xe_sriov_admin_bulk_set_preempt_timeout_us(pf_fd, 0);
> + igt_fail_on(fails);
> +}
> +
> +static void build_common_sched_priority_choice(int pf_fd, int num_vfs,
> + struct igt_sysfs_choice *common)
> +{
> + int ret;
> +
> + /* Start from PF */
> + ret = __xe_sriov_admin_get_sched_priority_choice(pf_fd, 0, common);
> + igt_require_f(ret == 0,
> + "Failed to read PF sched_priority (ret=%d)\n", ret);
> +
> + igt_require_f(common->num_tokens > 0,
> + "PF sched_priority exposes no tokens\n");
> +
> + /* Intersect with every VF 1..num_vfs */
> + for (int vf = 1; vf <= num_vfs; vf++) {
> + struct igt_sysfs_choice prio = {};
> +
> + ret = __xe_sriov_admin_get_sched_priority_choice(pf_fd, vf, &prio);
> + igt_require_f(ret == 0,
> + "Failed to read VF%u sched_priority (ret=%d)\n",
> + vf, ret);
> +
> + ret = igt_sysfs_choice_intersect(common, &prio);
> + igt_require_f(ret == 0,
> + "No common sched_priority between PF and VF%u\n",
> + vf);
> + }
> +
> + igt_require_f(common->num_tokens > 0,
> + "No common sched_priority across PF and all VFs\n");
> +
> + if (common->selected < 0) {
> + igt_debug("Common sched_priority has no selected token, "
> + "defaulting to tokens[0]=\"%s\"\n",
> + common->tokens[0]);
> + common->selected = 0;
> + }
> +}
> +
> +/**
> + * SUBTEST: bulk-sched-priority-vfs-disabled
> + * Description: Verify bulk sched_priority modification with VFs disabled.
> + */
> +static void bulk_set_sched_priority(int pf_fd, unsigned int total_vfs, const char *prio_str)
> +{
> + struct igt_sysfs_choice read_val;
> + const char *selected;
> + unsigned int id;
> + int fails = 0;
> +
> + xe_sriov_admin_bulk_set_sched_priority_string(pf_fd, prio_str);
> +
> + for (id = 0; id <= total_vfs; ++id) {
> + int ret = __xe_sriov_admin_get_sched_priority_choice(pf_fd, id,
> + &read_val);
> +
> + if (ret) {
> + igt_debug("%s: failed to read sched_priority, ret=%d\n",
> + igt_sriov_func_str(id), ret);
> + fails++;
> + continue;
> + }
> +
> + selected = igt_sysfs_choice_selected(&read_val);
> + if (!selected || strncmp(selected, prio_str, strlen(prio_str))) {
> + igt_debug("%s: sched_priority='%s', expected='%s'\n",
> + igt_sriov_func_str(id), selected ?: "NULL", prio_str);
> + fails++;
> + }
> + }
> +
> + igt_fail_on(fails);
> +}
> +
> +/**
> + * SUBTEST: sched-priority-vf-write-denied
> + * Description:
> + * Verify that sched_priority cannot be modified on a VF.
> + * A write attempt must fail with -EPERM or -EACCES and the
> + * current priority selection must remain unchanged.
> + */
> +static void sched_priority_vf_write_denied(int pf_fd, unsigned int vf_num)
> +{
> + struct igt_sysfs_choice before, after;
> + const char *new_token;
> + const char *baseline;
> + int baseline_selected;
> + bool attempted = false;
> + int ret;
> +
> + igt_require(vf_num > 0);
> +
> + ret = __xe_sriov_admin_get_sched_priority_choice(pf_fd, vf_num, &before);
> + igt_require(ret == 0);
> + igt_require(before.num_tokens > 0);
> + igt_require(before.selected >= 0);
> +
> + baseline_selected = before.selected;
> + baseline = igt_sysfs_choice_selected(&before);
> + igt_require(baseline);
> +
> + for (size_t i = 0; i < before.num_tokens; i++) {
> + if (before.num_tokens > 1 && (int)i == baseline_selected)
> + continue;
> +
> + new_token = before.tokens[i];
> + attempted = true;
> +
> + ret = __xe_sriov_admin_set_sched_priority_string(pf_fd, vf_num,
> + new_token);
> + igt_assert_f(ret == -EPERM || ret == -EACCES,
> + "Expected -EPERM/-EACCES when writing VF sched_priority "
> + "(token='%s'), got %d\n", new_token, ret);
> +
> + ret = __xe_sriov_admin_get_sched_priority_choice(pf_fd, vf_num,
> + &after);
> + igt_assert_eq(ret, 0);
> +
> + igt_assert_eq(after.selected, baseline_selected);
> + igt_assert(!strcmp(baseline, igt_sysfs_choice_selected(&after)));
> + }
> +
> + igt_assert(attempted);
> +}
> +
> +int igt_main()
> +{
> + unsigned int total_vfs;
> + int pf_fd;
> +
> + igt_fixture() {
> + pf_fd = drm_open_driver(DRIVER_XE);
> + igt_require(igt_sriov_is_pf(pf_fd));
> + igt_require(igt_sriov_get_enabled_vfs(pf_fd) == 0);
> + igt_require(xe_sriov_admin_is_present(pf_fd));
> + total_vfs = igt_sriov_get_total_vfs(pf_fd);
> + }
> +
> + igt_subtest_with_dynamic("default-sched-attributes-vfs-disabled") {
> + for (unsigned int id = 0; id <= total_vfs; ++id)
> + default_sched_attributes(pf_fd, id);
> + }
> +
> + igt_subtest_with_dynamic("exec-quantum-write-readback-vfs-disabled") {
> + uint32_t eq_ms = 10;
> +
> + for (unsigned int id = 0; id <= total_vfs; ++id) {
> + igt_dynamic_f("%s-eq_ms-%u", igt_sriov_func_str(id), eq_ms) {
> + exec_quantum_write_readback(pf_fd, id, eq_ms);
> + }
> + }
> + }
> +
> + igt_subtest_with_dynamic("preempt-timeout-write-readback-vfs-disabled") {
> + uint32_t pt_us = 20000;
> +
> + for (unsigned int id = 0; id <= total_vfs; ++id) {
> + igt_dynamic_f("%s-pt_us-%u", igt_sriov_func_str(id), pt_us) {
> + preempt_timeout_write_readback(pf_fd, id, pt_us);
> + }
> + }
> + }
> +
> + igt_subtest_with_dynamic("sched-priority-write-readback-vfs-disabled") {
> + for (unsigned int id = 0; id <= total_vfs; ++id) {
> + igt_dynamic_f("%s", igt_sriov_func_str(id)) {
> + sched_priority_write_readback(pf_fd, id);
> + }
> + }
> + }
> +
> + igt_subtest_with_dynamic("sched-priority-vf-write-denied") {
> + for_each_sriov_num_vfs(pf_fd, vf_num) {
> + igt_dynamic_f("%s", igt_sriov_func_str(vf_num)) {
> + sched_priority_vf_write_denied(pf_fd, vf_num);
> + }
> + }
> + }
> +
> + igt_subtest("bulk-exec-quantum-vfs-disabled") {
> + const uint32_t eq_ms = 10;
> +
> + bulk_set_exec_quantum(pf_fd, total_vfs, eq_ms);
> + }
> +
> + igt_subtest("bulk-preempt-timeout-vfs-disabled") {
> + uint32_t pt_us = 10000;
> +
> + bulk_set_preempt_timeout(pf_fd, total_vfs, pt_us);
> + }
> +
> + igt_subtest_group() {
> + struct igt_sysfs_choice prio = {};
> +
> + igt_fixture() {
> + build_common_sched_priority_choice(pf_fd, total_vfs,
> + &prio);
> + }
> +
> + igt_subtest_with_dynamic_f("bulk-sched-priority-vfs-disabled") {
> + for (size_t i = prio.num_tokens; i-- > 0; ) {
> + const char *prio_str = prio.tokens[i];
> +
> + igt_dynamic_f("%s", prio_str)
> + bulk_set_sched_priority(pf_fd, 0, prio_str);
> + }
> + }
> + }
> +
> + igt_fixture() {
> + int ret;
> +
> + ret = __xe_sriov_admin_bulk_restore_defaults(pf_fd);
> + igt_sriov_disable_vfs(pf_fd);
> + /* abort to avoid execution of next tests with enabled VFs */
> + igt_abort_on_f(igt_sriov_get_enabled_vfs(pf_fd) > 0,
> + "Failed to disable VF(s)");
> + igt_abort_on_f(ret, "Failed to restore default profile values\n");
> + drm_close_driver(pf_fd);
> + }
> +}
> diff --git a/tests/meson.build b/tests/meson.build
> index 0ad728b87..ef4edaa0d 100644
> --- a/tests/meson.build
> +++ b/tests/meson.build
> @@ -331,6 +331,7 @@ intel_xe_progs = [
> 'xe_vm',
> 'xe_waitfence',
> 'xe_spin_batch',
> + 'xe_sriov_admin',
> 'xe_sriov_auto_provisioning',
> 'xe_sriov_flr',
> 'xe_sriov_scheduling',
^ permalink raw reply [flat|nested] 19+ messages in thread
* ✓ Xe.CI.BAT: success for Xe SR-IOV admin scheduling helpers and test updates (rev3)
2026-01-28 18:08 [PATCH v3 i-g-t 00/10] Xe SR-IOV admin scheduling helpers and test updates Marcin Bernatowicz
` (9 preceding siblings ...)
2026-01-28 18:08 ` [PATCH v3 i-g-t 10/10] tests/intel/xe_sriov_admin: Add SR-IOV admin sysfs scheduling attributes tests Marcin Bernatowicz
@ 2026-01-28 20:32 ` Patchwork
2026-01-28 20:47 ` ✗ i915.CI.BAT: failure " Patchwork
11 siblings, 0 replies; 19+ messages in thread
From: Patchwork @ 2026-01-28 20:32 UTC (permalink / raw)
To: Marcin Bernatowicz; +Cc: igt-dev
[-- Attachment #1: Type: text/plain, Size: 781 bytes --]
== Series Details ==
Series: Xe SR-IOV admin scheduling helpers and test updates (rev3)
URL : https://patchwork.freedesktop.org/series/157591/
State : success
== Summary ==
CI Bug Log - changes from XEIGT_8723_BAT -> XEIGTPW_14443_BAT
====================================================
Summary
-------
**SUCCESS**
No regressions found.
Participating hosts (12 -> 11)
------------------------------
Missing (1): bat-bmg-3
Changes
-------
No changes found
Build changes
-------------
* IGT: IGT_8723 -> IGTPW_14443
IGTPW_14443: 14443
IGT_8723: 8723
xe-4465-8059f097e25f736bb3da09af6a9b283079abfd4f: 8059f097e25f736bb3da09af6a9b283079abfd4f
== Logs ==
For more details see: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_14443/index.html
[-- Attachment #2: Type: text/html, Size: 1326 bytes --]
^ permalink raw reply [flat|nested] 19+ messages in thread* ✗ i915.CI.BAT: failure for Xe SR-IOV admin scheduling helpers and test updates (rev3)
2026-01-28 18:08 [PATCH v3 i-g-t 00/10] Xe SR-IOV admin scheduling helpers and test updates Marcin Bernatowicz
` (10 preceding siblings ...)
2026-01-28 20:32 ` ✓ Xe.CI.BAT: success for Xe SR-IOV admin scheduling helpers and test updates (rev3) Patchwork
@ 2026-01-28 20:47 ` Patchwork
2026-01-29 10:11 ` Bernatowicz, Marcin
11 siblings, 1 reply; 19+ messages in thread
From: Patchwork @ 2026-01-28 20:47 UTC (permalink / raw)
To: Marcin Bernatowicz; +Cc: igt-dev
[-- Attachment #1: Type: text/plain, Size: 6127 bytes --]
== Series Details ==
Series: Xe SR-IOV admin scheduling helpers and test updates (rev3)
URL : https://patchwork.freedesktop.org/series/157591/
State : failure
== Summary ==
CI Bug Log - changes from IGT_8723 -> IGTPW_14443
====================================================
Summary
-------
**FAILURE**
Serious unknown changes coming with IGTPW_14443 absolutely need to be
verified manually.
If you think the reported changes have nothing to do with the changes
introduced in IGTPW_14443, please notify your bug team (I915-ci-infra@lists.freedesktop.org) to allow them
to document this new failure mode, which will reduce false positives in CI.
External URL: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_14443/index.html
Participating hosts (42 -> 41)
------------------------------
Additional (1): bat-adls-6
Missing (2): bat-dg2-13 fi-snb-2520m
Possible new issues
-------------------
Here are the unknown changes that may have been introduced in IGTPW_14443:
### IGT changes ###
#### Possible regressions ####
* igt@i915_pm_rpm@module-reload:
- bat-adlp-6: [PASS][1] -> [DMESG-WARN][2] +78 other tests dmesg-warn
[1]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_8723/bat-adlp-6/igt@i915_pm_rpm@module-reload.html
[2]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_14443/bat-adlp-6/igt@i915_pm_rpm@module-reload.html
Known issues
------------
Here are the changes found in IGTPW_14443 that come from known issues:
### IGT changes ###
#### Issues hit ####
* igt@gem_lmem_swapping@parallel-random-engines:
- bat-adls-6: NOTRUN -> [SKIP][3] ([i915#4613]) +3 other tests skip
[3]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_14443/bat-adls-6/igt@gem_lmem_swapping@parallel-random-engines.html
* igt@gem_tiled_pread_basic:
- bat-adls-6: NOTRUN -> [SKIP][4] ([i915#3282])
[4]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_14443/bat-adls-6/igt@gem_tiled_pread_basic.html
* igt@i915_selftest@live:
- bat-twl-1: [PASS][5] -> [DMESG-WARN][6] ([i915#14872]) +1 other test dmesg-warn
[5]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_8723/bat-twl-1/igt@i915_selftest@live.html
[6]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_14443/bat-twl-1/igt@i915_selftest@live.html
* igt@intel_hwmon@hwmon-read:
- bat-adls-6: NOTRUN -> [SKIP][7] ([i915#7707]) +1 other test skip
[7]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_14443/bat-adls-6/igt@intel_hwmon@hwmon-read.html
* igt@kms_cursor_legacy@basic-busy-flip-before-cursor-legacy:
- bat-adls-6: NOTRUN -> [SKIP][8] ([i915#4103]) +1 other test skip
[8]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_14443/bat-adls-6/igt@kms_cursor_legacy@basic-busy-flip-before-cursor-legacy.html
* igt@kms_dsc@dsc-basic:
- bat-adls-6: NOTRUN -> [SKIP][9] ([i915#3555] / [i915#3840])
[9]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_14443/bat-adls-6/igt@kms_dsc@dsc-basic.html
* igt@kms_force_connector_basic@force-load-detect:
- bat-adls-6: NOTRUN -> [SKIP][10]
[10]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_14443/bat-adls-6/igt@kms_force_connector_basic@force-load-detect.html
* igt@kms_pm_backlight@basic-brightness:
- bat-adls-6: NOTRUN -> [SKIP][11] ([i915#5354])
[11]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_14443/bat-adls-6/igt@kms_pm_backlight@basic-brightness.html
* igt@kms_psr@psr-primary-mmap-gtt:
- bat-adls-6: NOTRUN -> [SKIP][12] ([i915#1072] / [i915#9732]) +3 other tests skip
[12]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_14443/bat-adls-6/igt@kms_psr@psr-primary-mmap-gtt.html
* igt@kms_setmode@basic-clone-single-crtc:
- bat-adls-6: NOTRUN -> [SKIP][13] ([i915#3555])
[13]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_14443/bat-adls-6/igt@kms_setmode@basic-clone-single-crtc.html
* igt@prime_vgem@basic-fence-read:
- bat-adls-6: NOTRUN -> [SKIP][14] ([i915#3291]) +2 other tests skip
[14]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_14443/bat-adls-6/igt@prime_vgem@basic-fence-read.html
#### Possible fixes ####
* igt@i915_selftest@live:
- bat-mtlp-8: [DMESG-FAIL][15] ([i915#12061]) -> [PASS][16] +1 other test pass
[15]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_8723/bat-mtlp-8/igt@i915_selftest@live.html
[16]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_14443/bat-mtlp-8/igt@i915_selftest@live.html
* igt@i915_selftest@live@workarounds:
- bat-arls-6: [DMESG-FAIL][17] ([i915#12061]) -> [PASS][18] +1 other test pass
[17]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_8723/bat-arls-6/igt@i915_selftest@live@workarounds.html
[18]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_14443/bat-arls-6/igt@i915_selftest@live@workarounds.html
[i915#1072]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/1072
[i915#12061]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/12061
[i915#14872]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/14872
[i915#3282]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/3282
[i915#3291]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/3291
[i915#3555]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/3555
[i915#3840]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/3840
[i915#4103]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/4103
[i915#4613]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/4613
[i915#5354]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/5354
[i915#7707]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/7707
[i915#9732]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/9732
Build changes
-------------
* CI: CI-20190529 -> None
* IGT: IGT_8723 -> IGTPW_14443
CI-20190529: 20190529
CI_DRM_17900: 8059f097e25f736bb3da09af6a9b283079abfd4f @ git://anongit.freedesktop.org/gfx-ci/linux
IGTPW_14443: 14443
IGT_8723: 8723
== Logs ==
For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_14443/index.html
[-- Attachment #2: Type: text/html, Size: 7244 bytes --]
^ permalink raw reply [flat|nested] 19+ messages in thread