summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGustavo Sousa <gustavo.sousa@intel.com>2026-05-22 05:45:22 -0300
committerGustavo Sousa <gustavo.sousa@intel.com>2026-05-22 10:52:29 -0300
commitdf07911cb72dabebec3dd18d94c33f9ced74c3d6 (patch)
tree49660be7580d5bf9b4529ad0765fb07afa7b85cd
parent0da9ab6c4e12e66dbd2e8f54481662225a79b7f5 (diff)
drm/xe/rtp: Implement a structured parser for rule matching
The current unwritten grammar for RTP rules is as follows: rules = disjunction; disjunction = conjunction, { "OR", conjunction }; conjunction = single_rule, { single_rule }; (* the AND operator is implicit *) single_rule = ? GRAPHICS_VERSION(...), MEDIA_VERSION(...), FUNC(...), etc ? While rule_matches() currently works for the grammar above, it doesn't easily resemble it. Let's replace it with an implementation that is structured in a way to resemble the grammar. Such a new implementation, although a bit more verbose, is arguably easier to reason about and to adapt to any extension we do to the grammer in the future. Also take this opportunity to update the kernel-doc for XE_RTP_RULES() to include the grammar, so that it is not unwritten anymore. v2: - Include the grammar in the code documentation. (Matt) Reviewed-by: Matt Roper <matthew.d.roper@intel.com> Reviewed-by: Violet Monti <violet.monti@intel.com> Link: https://patch.msgid.link/20260522-rtp-rule-parser-v3-7-0c51039899f4@intel.com Signed-off-by: Gustavo Sousa <gustavo.sousa@intel.com>
-rw-r--r--drivers/gpu/drm/xe/xe_rtp.c138
-rw-r--r--drivers/gpu/drm/xe/xe_rtp.h29
2 files changed, 113 insertions, 54 deletions
diff --git a/drivers/gpu/drm/xe/xe_rtp.c b/drivers/gpu/drm/xe/xe_rtp.c
index 976a2e1f5592..dec9d94e6fb0 100644
--- a/drivers/gpu/drm/xe/xe_rtp.c
+++ b/drivers/gpu/drm/xe/xe_rtp.c
@@ -30,11 +30,28 @@ static bool has_samedia(const struct xe_device *xe)
return xe->info.media_verx100 >= 1300;
}
-static bool rule_match_item(const struct xe_device *xe,
- struct xe_gt *gt,
- struct xe_hw_engine *hwe,
- const struct xe_rtp_rule *r)
+struct rule_match_ctx {
+ const struct xe_device *xe;
+ struct xe_gt *gt;
+ struct xe_hw_engine *hwe;
+ const struct xe_rtp_rule *rules;
+ const unsigned int n_rules;
+ unsigned int head;
+ int err;
+};
+
+static bool rule_is_item(const struct xe_rtp_rule *r)
+{
+ return r->match_type != XE_RTP_MATCH_OR;
+}
+
+static bool rule_match_item(struct rule_match_ctx *match_ctx)
{
+ const struct xe_device *xe = match_ctx->xe;
+ struct xe_gt *gt = match_ctx->gt;
+ struct xe_hw_engine *hwe = match_ctx->hwe;
+ const struct xe_rtp_rule *r = &match_ctx->rules[match_ctx->head];
+
switch (r->match_type) {
case XE_RTP_MATCH_PLATFORM:
return xe->info.platform == r->platform;
@@ -120,6 +137,63 @@ static bool rule_match_item(const struct xe_device *xe,
}
}
+/*
+ * Match a conjunctive set of rules (rules joined by an implicit "AND").
+ *
+ * Once one item evaluates to false, the remaining items are not evaluated
+ * anymore. Nevetheless, all rules are consumed to allow detecting syntax
+ * errors.
+ */
+static bool rule_match_and(struct rule_match_ctx *match_ctx, bool parse_only)
+{
+ bool match = true;
+ unsigned int count = 0;
+
+ while (match_ctx->head < match_ctx->n_rules &&
+ rule_is_item(&match_ctx->rules[match_ctx->head])) {
+ if (!parse_only)
+ match = rule_match_item(match_ctx);
+
+ if (!match)
+ parse_only = true;
+
+ match_ctx->head++;
+ count++;
+ }
+
+ if (drm_WARN_ON(&match_ctx->xe->drm, !count)) {
+ match_ctx->err = -EINVAL;
+
+ if (!parse_only)
+ match = false;
+ }
+
+ return match;
+}
+
+/*
+ * Match a disjunctive set of rules (subset of rules joined by
+ * "XE_RTP_MATCH_OR").
+ *
+ * Once one subset evaluates to true, the remaining items are not evaluated
+ * anymore. Nevetheless, all rules are consumed to allow detecting syntax
+ * errors.
+ */
+static bool rule_match_or(struct rule_match_ctx *match_ctx)
+{
+ bool match = rule_match_and(match_ctx, false);
+
+ while (match_ctx->head < match_ctx->n_rules &&
+ match_ctx->rules[match_ctx->head].match_type == XE_RTP_MATCH_OR) {
+ /* Consume XE_RTP_MATCH_OR. */
+ match_ctx->head++;
+
+ match = rule_match_and(match_ctx, match);
+ }
+
+ return match;
+}
+
static bool rule_matches_with_err(const struct xe_device *xe,
struct xe_gt *gt,
struct xe_hw_engine *hwe,
@@ -127,55 +201,19 @@ static bool rule_matches_with_err(const struct xe_device *xe,
unsigned int n_rules,
int *err)
{
- const struct xe_rtp_rule *r;
- unsigned int i, rcount = 0;
- bool short_circuit_or = false;
+ struct rule_match_ctx match_ctx = {
+ .xe = xe,
+ .gt = gt,
+ .hwe = hwe,
+ .rules = rules,
+ .n_rules = n_rules,
+ };
+ bool match = rule_match_or(&match_ctx);
if (err)
- *err = 0;
-
- for (r = rules, i = 0; i < n_rules; r = &rules[++i]) {
- if (r->match_type == XE_RTP_MATCH_OR) {
- if (drm_WARN_ON(&xe->drm, !rcount)) {
- if (err)
- *err = -EINVAL;
- continue;
- }
-
- /*
- * This is only reached if a complete conjunction of
- * rules passed, in which case we short-circuit rule
- * evaluation, but still keep parsing to find any syntax
- * errors.
- */
- short_circuit_or = true;
- rcount = 0;
- continue;
- }
-
- if (short_circuit_or || rule_match_item(xe, gt, hwe, r)) {
- rcount++;
- } else {
- /*
- * Advance rules until we find XE_RTP_MATCH_OR to check
- * if there's another set of conditions to check
- */
- while (++i < n_rules && rules[i].match_type != XE_RTP_MATCH_OR)
- ;
-
- if (i >= n_rules)
- return false;
-
- rcount = 0;
- }
- }
-
- if (drm_WARN_ON(&xe->drm, !rcount)) {
- if (err)
- *err = -EINVAL;
- }
+ *err = match_ctx.err;
- return short_circuit_or || rcount;
+ return match;
}
static bool rule_matches(const struct xe_device *xe,
diff --git a/drivers/gpu/drm/xe/xe_rtp.h b/drivers/gpu/drm/xe/xe_rtp.h
index 562082b18d7b..e4f1930ca1c3 100644
--- a/drivers/gpu/drm/xe/xe_rtp.h
+++ b/drivers/gpu/drm/xe/xe_rtp.h
@@ -394,18 +394,39 @@ struct xe_reg_sr;
* XE_RTP_RULES - Helper to set multiple rules to a struct xe_rtp_entry_sr entry
* @...: Rules
*
- * At least one rule is needed and up to 12 are supported. Multiple rules are
- * AND'ed together, i.e. all the rules must evaluate to true for the entry to
- * be processed. See XE_RTP_MATCH_* for the possible match rules. Example:
+ * When an RTP table is being processed, the rules of each entry are evaluated
+ * to check if they match the target entity (platform, gt or hwe, depending on
+ * the specific RTP table).
+ *
+ * The sequence of arguments of this macro must follow the following eBNF
+ * grammar::
+ *
+ * rules = disjunction;
+ * disjunction = conjunction, { "OR", conjunction };
+ * conjunction = single_rule, { single_rule };
+ * (* the AND operator is implicit *)
+ * single_rule = ? GRAPHICS_VERSION(...), MEDIA_VERSION(...),
+ * FUNC(...), etc ?
+ *
+ * Examples:
*
* .. code-block:: c
*
* const struct xe_rtp_entry_sr wa_entries[] = {
* ...
- * { XE_RTP_NAME("test-entry"),
+ * { XE_RTP_NAME("entry-a"),
+ * // Match DG2-G10 with graphics steppings A0 up-to B0
+ * // (exclusive).
* XE_RTP_RULES(SUBPLATFORM(DG2, G10), GRAPHICS_STEP(A0, B0)),
* ...
* },
+ * { XE_RTP_NAME("entry-b"),
+ * // Match graphics version 20 (all steppings) or graphics
+ * // version 30 steppings A0 up-to B0 (exclusive).
+ * XE_RTP_RULES(GRAPHICS_VERSION(2000), OR,
+ * GRAPHICS_VERSION(3000), GRAPHICS_STEP(A0, B0))
+ * ...
+ * },
* ...
* };
*/