aboutsummaryrefslogtreecommitdiffstats
diff options
authorMark Brown <broonie@kernel.org>2026-05-29 22:42:19 +0100
committerMark Brown <broonie@kernel.org>2026-05-29 22:42:19 +0100
commit062cbcbe2293138856bd93c7bbf269b1d88ee2ae (patch)
tree1086ad305bae999f0a1e0c6b112634fbed9574e3
parent945aebe6ed18f5fd87139baafb7a0f9bace7e2ff (diff)
parent41e328c62a5662459dcb49cb995ebd5c13179b39 (diff)
downloadlinux-next-history-062cbcbe2293138856bd93c7bbf269b1d88ee2ae.tar.gz
Merge branch 'drm-xe-next' of https://gitlab.freedesktop.org/drm/xe/kernel.git
-rw-r--r--Documentation/gpu/xe/xe_firmware.rst4
-rw-r--r--drivers/gpu/drm/xe/abi/uc_fw_abi.h (renamed from drivers/gpu/drm/xe/xe_uc_fw_abi.h)4
-rw-r--r--drivers/gpu/drm/xe/tests/xe_pci.c6
-rw-r--r--drivers/gpu/drm/xe/tests/xe_rtp.c38
-rw-r--r--drivers/gpu/drm/xe/tests/xe_rtp_test.c327
-rw-r--r--drivers/gpu/drm/xe/tests/xe_rtp_test.h23
-rw-r--r--drivers/gpu/drm/xe/xe_device.c57
-rw-r--r--drivers/gpu/drm/xe/xe_device.h4
-rw-r--r--drivers/gpu/drm/xe/xe_eu_stall.c5
-rw-r--r--drivers/gpu/drm/xe/xe_ggtt.c8
-rw-r--r--drivers/gpu/drm/xe/xe_guc_submit.c72
-rw-r--r--drivers/gpu/drm/xe/xe_late_bind_fw_types.h3
-rw-r--r--drivers/gpu/drm/xe/xe_oa.c25
-rw-r--r--drivers/gpu/drm/xe/xe_observation.c32
-rw-r--r--drivers/gpu/drm/xe/xe_observation.h3
-rw-r--r--drivers/gpu/drm/xe/xe_pci.c27
-rw-r--r--drivers/gpu/drm/xe/xe_pm.c42
-rw-r--r--drivers/gpu/drm/xe/xe_pm.h1
-rw-r--r--drivers/gpu/drm/xe/xe_rtp.c297
-rw-r--r--drivers/gpu/drm/xe/xe_rtp.h29
-rw-r--r--drivers/gpu/drm/xe/xe_uc_fw.h2
-rw-r--r--include/linux/perf_event.h31
-rw-r--r--kernel/events/core.c18
23 files changed, 706 insertions, 352 deletions
diff --git a/Documentation/gpu/xe/xe_firmware.rst b/Documentation/gpu/xe/xe_firmware.rst
index 9c15a300bc625..d3030d1c9a845 100644
--- a/Documentation/gpu/xe/xe_firmware.rst
+++ b/Documentation/gpu/xe/xe_firmware.rst
@@ -7,10 +7,10 @@ Firmware
Firmware Layout
===============
-.. kernel-doc:: drivers/gpu/drm/xe/xe_uc_fw_abi.h
+.. kernel-doc:: drivers/gpu/drm/xe/abi/uc_fw_abi.h
:doc: CSS-based Firmware Layout
-.. kernel-doc:: drivers/gpu/drm/xe/xe_uc_fw_abi.h
+.. kernel-doc:: drivers/gpu/drm/xe/abi/uc_fw_abi.h
:doc: GSC-based Firmware Layout
Write Once Protected Content Memory (WOPCM) Layout
diff --git a/drivers/gpu/drm/xe/xe_uc_fw_abi.h b/drivers/gpu/drm/xe/abi/uc_fw_abi.h
index 74b888904fdc7..198e949660e09 100644
--- a/drivers/gpu/drm/xe/xe_uc_fw_abi.h
+++ b/drivers/gpu/drm/xe/abi/uc_fw_abi.h
@@ -3,8 +3,8 @@
* Copyright © 2022 Intel Corporation
*/
-#ifndef _XE_UC_FW_ABI_H_
-#define _XE_UC_FW_ABI_H_
+#ifndef _ABI_UC_FW_ABI_H
+#define _ABI_UC_FW_ABI_H
#include <linux/build_bug.h>
#include <linux/types.h>
diff --git a/drivers/gpu/drm/xe/tests/xe_pci.c b/drivers/gpu/drm/xe/tests/xe_pci.c
index 860409c579f8c..9240aff779da3 100644
--- a/drivers/gpu/drm/xe/tests/xe_pci.c
+++ b/drivers/gpu/drm/xe/tests/xe_pci.c
@@ -311,6 +311,11 @@ const void *xe_pci_id_gen_param(struct kunit *test, const void *prev, char *desc
}
EXPORT_SYMBOL_IF_KUNIT(xe_pci_id_gen_param);
+static void fake_init_devid(struct xe_device *xe)
+{
+ /* Nothing to do, just keep zero. */
+}
+
static int fake_read_gmdid(struct xe_device *xe, enum xe_gmdid_type type,
u32 *ver, u32 *revid)
{
@@ -369,6 +374,7 @@ done:
xe->sriov.__mode = data && data->sriov_mode ?
data->sriov_mode : XE_SRIOV_MODE_NONE;
+ kunit_activate_static_stub(test, init_devid, fake_init_devid);
kunit_activate_static_stub(test, read_gmdid, fake_read_gmdid);
kunit_activate_static_stub(test, xe_info_probe_tile_count,
fake_xe_info_probe_tile_count);
diff --git a/drivers/gpu/drm/xe/tests/xe_rtp.c b/drivers/gpu/drm/xe/tests/xe_rtp.c
new file mode 100644
index 0000000000000..b3a8b75936d11
--- /dev/null
+++ b/drivers/gpu/drm/xe/tests/xe_rtp.c
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0 AND MIT
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#include "tests/xe_rtp_test.h"
+
+#include <kunit/visibility.h>
+
+/**
+ * xe_rtp_rule_matches - Check if a set of RTP rule set match against the
+ * device/GT/hwe
+ * @xe: The xe device
+ * @gt: The GT struct (may be NULL)
+ * @hwe: The hw_engine (may be NULL)
+ * @rules: The array of rules to match against
+ * @n_rules: Number of items in @rules
+ * @err: Pointer (may be NULL) to set error number.
+ *
+ * This parses the set of rules and check if they match against the passed
+ * parameters.
+ *
+ * If passed, @err is updated with a non-zero negative error number or zero if
+ * no errors were found during the parsing/evaluation of rules.
+ *
+ * Returns true if there is a match and false if there is no match or if an
+ * error was found.
+ */
+bool xe_rtp_rule_matches(const struct xe_device *xe,
+ struct xe_gt *gt,
+ struct xe_hw_engine *hwe,
+ const struct xe_rtp_rule *rules,
+ unsigned int n_rules,
+ int *err)
+{
+ return rule_matches_with_err(xe, gt, hwe, rules, n_rules, err);
+}
+EXPORT_SYMBOL_IF_KUNIT(xe_rtp_rule_matches);
diff --git a/drivers/gpu/drm/xe/tests/xe_rtp_test.c b/drivers/gpu/drm/xe/tests/xe_rtp_test.c
index 5d78f2283df93..642f6e090ad0f 100644
--- a/drivers/gpu/drm/xe/tests/xe_rtp_test.c
+++ b/drivers/gpu/drm/xe/tests/xe_rtp_test.c
@@ -21,6 +21,7 @@
#include "xe_pci_test.h"
#include "xe_reg_sr.h"
#include "xe_rtp.h"
+#include "xe_rtp_test.h"
#define REGULAR_REG1 XE_REG(1)
#define REGULAR_REG2 XE_REG(2)
@@ -37,6 +38,14 @@
#undef XE_REG_MCR
#define XE_REG_MCR(...) XE_REG(__VA_ARGS__, .mcr = 1)
+struct rtp_rules_test_case {
+ const char *name;
+ bool expected_match;
+ int expected_err;
+ const struct xe_rtp_rule *rules;
+ u8 n_rules;
+};
+
struct rtp_to_sr_test_case {
const char *name;
struct xe_reg expected_reg;
@@ -83,6 +92,194 @@ static bool match_no(const struct xe_device *xe, const struct xe_gt *gt,
return false;
}
+static const struct rtp_rules_test_case rtp_rules_cases[] = {
+ /*
+ * Single rules.
+ *
+ * TODO: Include other types of rules as well: GRAPHICS_VERSION(),
+ * MEDIA_VERSION(), etc.
+ */
+ {
+ .name = "no",
+ .expected_match = false,
+ XE_RTP_RULES(FUNC(match_no)),
+ },
+ {
+ .name = "yes",
+ .expected_match = true,
+ XE_RTP_RULES(FUNC(match_yes)),
+ },
+
+ /* Conjunctions with 2 operands. */
+ {
+ .name = "no-and-no",
+ .expected_match = false,
+ XE_RTP_RULES(FUNC(match_no), FUNC(match_no)),
+ },
+ {
+ .name = "no-and-yes",
+ .expected_match = false,
+ XE_RTP_RULES(FUNC(match_no), FUNC(match_yes)),
+ },
+ {
+ .name = "yes-and-no",
+ .expected_match = false,
+ XE_RTP_RULES(FUNC(match_yes), FUNC(match_no)),
+ },
+ {
+ .name = "yes-and-yes",
+ .expected_match = true,
+ XE_RTP_RULES(FUNC(match_yes), FUNC(match_yes)),
+ },
+
+ /* Disjunctions with 2 operands. */
+ {
+ .name = "no-or-no",
+ .expected_match = false,
+ XE_RTP_RULES(FUNC(match_no), OR, FUNC(match_no)),
+ },
+ {
+ .name = "no-or-yes",
+ .expected_match = true,
+ XE_RTP_RULES(FUNC(match_no), OR, FUNC(match_yes)),
+ },
+ {
+ .name = "yes-or-no",
+ .expected_match = true,
+ XE_RTP_RULES(FUNC(match_yes), OR, FUNC(match_no)),
+ },
+ {
+ .name = "yes-or-yes",
+ .expected_match = true,
+ XE_RTP_RULES(FUNC(match_yes), OR, FUNC(match_yes)),
+ },
+
+ /* Conjunction and disjunctions. */
+ {
+ .name = "no-yes-or-yes-no",
+ .expected_match = false,
+ XE_RTP_RULES(FUNC(match_no), FUNC(match_yes), OR,
+ FUNC(match_yes), FUNC(match_no)),
+ },
+ {
+ .name = "no-yes-or-yes-yes",
+ .expected_match = true,
+ XE_RTP_RULES(FUNC(match_no), FUNC(match_yes), OR,
+ FUNC(match_yes), FUNC(match_yes)),
+ },
+ {
+ .name = "yes-yes-or-no-yes",
+ .expected_match = true,
+ XE_RTP_RULES(FUNC(match_yes), FUNC(match_yes), OR,
+ FUNC(match_no), FUNC(match_yes)),
+ },
+ {
+ .name = "yes-yes-or-yes-yes",
+ .expected_match = true,
+ XE_RTP_RULES(FUNC(match_yes), FUNC(match_yes), OR,
+ FUNC(match_yes), FUNC(match_yes)),
+ },
+ {
+ .name = "no-no-or-yes-or-no",
+ .expected_match = true,
+ XE_RTP_RULES(FUNC(match_no), FUNC(match_no), OR,
+ FUNC(match_yes), OR,
+ FUNC(match_no)),
+ },
+
+ /* Syntax errors. */
+ {
+ .name = "or",
+ .expected_match = false,
+ .expected_err = -EINVAL,
+ XE_RTP_RULES(OR),
+ },
+ {
+ .name = "or-yes",
+ .expected_match = true,
+ .expected_err = -EINVAL,
+ XE_RTP_RULES(OR, FUNC(match_yes)),
+ },
+ {
+ .name = "or-no",
+ .expected_match = false,
+ .expected_err = -EINVAL,
+ XE_RTP_RULES(OR, FUNC(match_no)),
+ },
+ {
+ .name = "yes-or",
+ .expected_match = true,
+ .expected_err = -EINVAL,
+ XE_RTP_RULES(FUNC(match_yes), OR),
+ },
+ {
+ .name = "no-or",
+ .expected_match = false,
+ .expected_err = -EINVAL,
+ XE_RTP_RULES(FUNC(match_no), OR),
+ },
+ {
+ .name = "no-or-or-yes",
+ .expected_match = true,
+ .expected_err = -EINVAL,
+ XE_RTP_RULES(FUNC(match_no), OR, OR, FUNC(match_yes)),
+ },
+ {
+ .name = "yes-or-or-no",
+ .expected_match = true,
+ .expected_err = -EINVAL,
+ XE_RTP_RULES(FUNC(match_yes), OR, OR, FUNC(match_no)),
+ },
+ {
+ .name = "no-or-or-no",
+ .expected_match = false,
+ .expected_err = -EINVAL,
+ XE_RTP_RULES(FUNC(match_no), OR, OR, FUNC(match_no)),
+ },
+
+ /* No match because hwe is NULL. */
+ {
+ .name = "missing-context-engine-class",
+ .expected_match = false,
+ XE_RTP_RULES(ENGINE_CLASS(RENDER)),
+ },
+
+ /*
+ * Missing context (hwe==NULL) does not cause parsing to stop, hence we
+ * expect a match.
+ */
+ {
+ .name = "missing-context-engine-class-or-yes",
+ .expected_match = true,
+ XE_RTP_RULES(ENGINE_CLASS(RENDER), OR, FUNC(match_yes)),
+ },
+
+ /*
+ * Missing context (hwe==NULL) does not cause parsing to stop, hence we
+ * expect a syntax error.
+ */
+ {
+ .name = "missing-context-engine-class-or-or-yes",
+ .expected_match = true,
+ .expected_err = -EINVAL,
+ XE_RTP_RULES(ENGINE_CLASS(RENDER), OR, OR, FUNC(match_yes)),
+ },
+};
+
+static void xe_rtp_rules_tests(struct kunit *test)
+{
+ const struct rtp_rules_test_case *param = test->param_value;
+ struct xe_device *xe = test->priv;
+ struct xe_gt *gt = xe_device_get_root_tile(xe)->primary_gt;
+ int err;
+ bool match;
+
+ match = xe_rtp_rule_matches(xe, gt, NULL, param->rules, param->n_rules, &err);
+
+ KUNIT_EXPECT_EQ(test, match, param->expected_match);
+ KUNIT_EXPECT_EQ(test, err, param->expected_err);
+}
+
static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = {
{
.name = "coalesce-same-reg",
@@ -125,80 +322,6 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = {
},
},
{
- .name = "match-or",
- .expected_reg = REGULAR_REG1,
- .expected_set_bits = REG_BIT(0) | REG_BIT(1) | REG_BIT(2),
- .expected_clr_bits = REG_BIT(0) | REG_BIT(1) | REG_BIT(2),
- .expected_active = BIT(0) | BIT(1) | BIT(2),
- .expected_count_sr_entries = 1,
- .entries = (const struct xe_rtp_entry_sr[]) {
- { XE_RTP_NAME("first"),
- XE_RTP_RULES(FUNC(match_yes), OR, FUNC(match_no)),
- XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
- },
- { XE_RTP_NAME("middle"),
- XE_RTP_RULES(FUNC(match_no), FUNC(match_no), OR,
- FUNC(match_yes), OR,
- FUNC(match_no)),
- XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1)))
- },
- { XE_RTP_NAME("last"),
- XE_RTP_RULES(FUNC(match_no), OR, FUNC(match_yes)),
- XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(2)))
- },
- { XE_RTP_NAME("no-match"),
- XE_RTP_RULES(FUNC(match_no), OR, FUNC(match_no)),
- XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(3)))
- },
- {}
- },
- },
- {
- .name = "match-or-xfail",
- .expected_reg = REGULAR_REG1,
- .expected_count_sr_entries = 0,
- .entries = (const struct xe_rtp_entry_sr[]) {
- { XE_RTP_NAME("leading-or"),
- XE_RTP_RULES(OR, FUNC(match_yes)),
- XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
- },
- { XE_RTP_NAME("trailing-or"),
- /*
- * First condition is match_no, otherwise the failure
- * wouldn't really trigger as RTP stops processing as
- * soon as it has a matching set of rules
- */
- XE_RTP_RULES(FUNC(match_no), OR),
- XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1)))
- },
- { XE_RTP_NAME("no-or-or-yes"),
- XE_RTP_RULES(FUNC(match_no), OR, OR, FUNC(match_yes)),
- XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(2)))
- },
- {}
- },
- },
- {
- .name = "no-match-no-add-multiple-rules",
- .expected_reg = REGULAR_REG1,
- .expected_set_bits = REG_BIT(0),
- .expected_clr_bits = REG_BIT(0),
- .expected_active = BIT(0),
- .expected_count_sr_entries = 1,
- /* Don't coalesce second entry due to one of the rules */
- .entries = (const struct xe_rtp_entry_sr[]) {
- { XE_RTP_NAME("basic-1"),
- XE_RTP_RULES(FUNC(match_yes)),
- XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
- },
- { XE_RTP_NAME("basic-2"),
- XE_RTP_RULES(FUNC(match_yes), FUNC(match_no)),
- XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1)))
- },
- {}
- },
- },
- {
.name = "two-regs-two-entries",
.expected_reg = REGULAR_REG1,
.expected_set_bits = REG_BIT(0),
@@ -458,33 +581,15 @@ static const struct rtp_test_case rtp_cases[] = {
},
},
{
- .name = "inactive-1st_or_active-inactive",
+ .name = "inactive-active-inactive",
.expected_active = BIT(1),
.entries = (const struct xe_rtp_entry[]) {
{ XE_RTP_NAME("r1"),
XE_RTP_RULES(FUNC(match_no)),
},
- { XE_RTP_NAME("r2_or_conditions"),
- XE_RTP_RULES(FUNC(match_yes), OR,
- FUNC(match_no), OR,
- FUNC(match_no)) },
- { XE_RTP_NAME("r3"),
- XE_RTP_RULES(FUNC(match_no)),
- },
- {}
- },
- },
- {
- .name = "inactive-2nd_or_active-inactive",
- .expected_active = BIT(1),
- .entries = (const struct xe_rtp_entry[]) {
- { XE_RTP_NAME("r1"),
- XE_RTP_RULES(FUNC(match_no)),
+ { XE_RTP_NAME("r2"),
+ XE_RTP_RULES(FUNC(match_yes)),
},
- { XE_RTP_NAME("r2_or_conditions"),
- XE_RTP_RULES(FUNC(match_no), OR,
- FUNC(match_yes), OR,
- FUNC(match_no)) },
{ XE_RTP_NAME("r3"),
XE_RTP_RULES(FUNC(match_no)),
},
@@ -492,33 +597,15 @@ static const struct rtp_test_case rtp_cases[] = {
},
},
{
- .name = "inactive-last_or_active-inactive",
- .expected_active = BIT(1),
+ .name = "inactive-inactive-inactive",
+ .expected_active = 0,
.entries = (const struct xe_rtp_entry[]) {
{ XE_RTP_NAME("r1"),
XE_RTP_RULES(FUNC(match_no)),
},
- { XE_RTP_NAME("r2_or_conditions"),
- XE_RTP_RULES(FUNC(match_no), OR,
- FUNC(match_no), OR,
- FUNC(match_yes)) },
- { XE_RTP_NAME("r3"),
- XE_RTP_RULES(FUNC(match_no)),
- },
- {}
- },
- },
- {
- .name = "inactive-no_or_active-inactive",
- .expected_active = 0,
- .entries = (const struct xe_rtp_entry[]) {
- { XE_RTP_NAME("r1"),
+ { XE_RTP_NAME("r2"),
XE_RTP_RULES(FUNC(match_no)),
},
- { XE_RTP_NAME("r2_or_conditions"),
- XE_RTP_RULES(FUNC(match_no), OR,
- FUNC(match_no), OR,
- FUNC(match_no)) },
{ XE_RTP_NAME("r3"),
XE_RTP_RULES(FUNC(match_no)),
},
@@ -544,6 +631,13 @@ static void xe_rtp_process_tests(struct kunit *test)
KUNIT_EXPECT_EQ(test, active, param->expected_active);
}
+static void rtp_rules_desc(const struct rtp_rules_test_case *t, char *desc)
+{
+ strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
+}
+
+KUNIT_ARRAY_PARAM(rtp_rules, rtp_rules_cases, rtp_rules_desc);
+
static void rtp_to_sr_desc(const struct rtp_to_sr_test_case *t, char *desc)
{
strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
@@ -591,6 +685,7 @@ static void xe_rtp_test_exit(struct kunit *test)
}
static struct kunit_case xe_rtp_tests[] = {
+ KUNIT_CASE_PARAM(xe_rtp_rules_tests, rtp_rules_gen_params),
KUNIT_CASE_PARAM(xe_rtp_process_to_sr_tests, rtp_to_sr_gen_params),
KUNIT_CASE_PARAM(xe_rtp_process_tests, rtp_gen_params),
{}
diff --git a/drivers/gpu/drm/xe/tests/xe_rtp_test.h b/drivers/gpu/drm/xe/tests/xe_rtp_test.h
new file mode 100644
index 0000000000000..26becc1e2af04
--- /dev/null
+++ b/drivers/gpu/drm/xe/tests/xe_rtp_test.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 AND MIT */
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#ifndef _XE_RTP_TEST_H_
+#define _XE_RTP_TEST_H_
+
+#include <linux/types.h>
+
+struct xe_device;
+struct xe_gt;
+struct xe_hw_engine;
+struct xe_rtp_rule;
+
+bool xe_rtp_rule_matches(const struct xe_device *xe,
+ struct xe_gt *gt,
+ struct xe_hw_engine *hwe,
+ const struct xe_rtp_rule *rules,
+ unsigned int n_rules,
+ int *err);
+
+#endif
diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
index 576095cf09529..d224861b6f6fd 100644
--- a/drivers/gpu/drm/xe/xe_device.c
+++ b/drivers/gpu/drm/xe/xe_device.c
@@ -475,8 +475,15 @@ static void xe_device_destroy(struct drm_device *dev, void *dummy)
ttm_device_fini(&xe->ttm);
}
-struct xe_device *xe_device_create(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+/**
+ * xe_device_create() - Create a new &xe_device instance
+ * @pdev: the parent &pci_dev
+ *
+ * Allocate and initialize a device managed Xe device structure.
+ *
+ * Return: pointer to new &xe_device on success, or ERR_PTR on failure.
+ */
+struct xe_device *xe_device_create(struct pci_dev *pdev)
{
const struct drm_driver *driver = &regular_driver;
struct xe_device *xe;
@@ -499,30 +506,45 @@ struct xe_device *xe_device_create(struct pci_dev *pdev,
if (IS_ERR(xe))
return xe;
+ err = xe_device_init_early(xe);
+ if (err)
+ return ERR_PTR(err);
+
+ return xe;
+}
+ALLOW_ERROR_INJECTION(xe_device_create, ERRNO); /* See xe_pci_probe() */
+
+/**
+ * xe_device_init_early() - Initialize a new &xe_device instance
+ * @xe: the &xe_device to initialize
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int xe_device_init_early(struct xe_device *xe)
+{
+ int err;
+
err = ttm_device_init(&xe->ttm, &xe_ttm_funcs, xe->drm.dev,
xe->drm.anon_inode->i_mapping,
xe->drm.vma_offset_manager, 0);
- if (WARN_ON(err))
- return ERR_PTR(err);
+ if (err)
+ return err;
xe_bo_dev_init(&xe->bo_device);
err = drmm_add_action_or_reset(&xe->drm, xe_device_destroy, NULL);
if (err)
- return ERR_PTR(err);
+ return err;
err = xe_shrinker_create(xe);
if (err)
- return ERR_PTR(err);
+ return err;
- xe->info.devid = pdev->device;
- xe->info.revid = pdev->revision;
- xe->info.force_execlist = xe_modparam.force_execlist;
xe->atomic_svm_timeslice_ms = 5;
xe->min_run_period_lr_ms = 5;
err = xe_irq_init(xe);
if (err)
- return ERR_PTR(err);
+ return err;
xe_validation_device_init(&xe->val);
@@ -532,7 +554,7 @@ struct xe_device *xe_device_create(struct pci_dev *pdev,
err = xe_pagemap_shrinker_create(xe);
if (err)
- return ERR_PTR(err);
+ return err;
xa_init_flags(&xe->usm.asid_to_vm, XA_FLAGS_ALLOC);
@@ -551,7 +573,7 @@ struct xe_device *xe_device_create(struct pci_dev *pdev,
err = xe_bo_pinned_init(xe);
if (err)
- return ERR_PTR(err);
+ return err;
xe->preempt_fence_wq = alloc_ordered_workqueue("xe-preempt-fence-wq",
WQ_MEM_RECLAIM);
@@ -565,16 +587,19 @@ struct xe_device *xe_device_create(struct pci_dev *pdev,
* drmm_add_action_or_reset register above
*/
drm_err(&xe->drm, "Failed to allocate xe workqueues\n");
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
}
err = drmm_mutex_init(&xe->drm, &xe->pmt.lock);
if (err)
- return ERR_PTR(err);
+ return err;
- return xe;
+ err = xe_pm_init_early(xe);
+ if (err)
+ return err;
+
+ return 0;
}
-ALLOW_ERROR_INJECTION(xe_device_create, ERRNO); /* See xe_pci_probe() */
static bool xe_driver_flr_disabled(struct xe_device *xe)
{
diff --git a/drivers/gpu/drm/xe/xe_device.h b/drivers/gpu/drm/xe/xe_device.h
index 355d69dc8f545..975768a6a9c83 100644
--- a/drivers/gpu/drm/xe/xe_device.h
+++ b/drivers/gpu/drm/xe/xe_device.h
@@ -43,8 +43,8 @@ static inline struct xe_device *ttm_to_xe_device(struct ttm_device *ttm)
return container_of(ttm, struct xe_device, ttm);
}
-struct xe_device *xe_device_create(struct pci_dev *pdev,
- const struct pci_device_id *ent);
+struct xe_device *xe_device_create(struct pci_dev *pdev);
+int xe_device_init_early(struct xe_device *xe);
int xe_device_probe_early(struct xe_device *xe);
int xe_device_probe(struct xe_device *xe);
void xe_device_remove(struct xe_device *xe);
diff --git a/drivers/gpu/drm/xe/xe_eu_stall.c b/drivers/gpu/drm/xe/xe_eu_stall.c
index 297be3c42b208..d37770c58c5d3 100644
--- a/drivers/gpu/drm/xe/xe_eu_stall.c
+++ b/drivers/gpu/drm/xe/xe_eu_stall.c
@@ -985,9 +985,10 @@ int xe_eu_stall_stream_open(struct drm_device *dev, u64 data, struct drm_file *f
return -ENODEV;
}
- if (xe_observation_paranoid && !perfmon_capable()) {
+ ret = xe_observation_paranoid_check();
+ if (ret) {
drm_dbg(&xe->drm, "Insufficient privileges for EU stall monitoring\n");
- return -EACCES;
+ return ret;
}
/* Initialize and set default values */
diff --git a/drivers/gpu/drm/xe/xe_ggtt.c b/drivers/gpu/drm/xe/xe_ggtt.c
index a351c578b1705..8ec23862477fc 100644
--- a/drivers/gpu/drm/xe/xe_ggtt.c
+++ b/drivers/gpu/drm/xe/xe_ggtt.c
@@ -111,14 +111,14 @@ struct xe_ggtt_pt_ops {
struct xe_ggtt {
/** @tile: Back pointer to tile where this GGTT belongs */
struct xe_tile *tile;
- /** @start: Start offset of GGTT */
+ /** @start: Start offset of GGTT */
u64 start;
/** @size: Total usable size of this GGTT */
u64 size;
-
/**
- * @flags: Flags for this GGTT
+ * @flags: Flags for this GGTT.
* Acceptable flags:
+ *
* - %XE_GGTT_FLAGS_64K - if PTE size is 64K. Otherwise, regular is 4K.
* - %XE_GGTT_FLAGS_ONLINE - is GGTT online, protected by ggtt->lock
* after init
@@ -129,7 +129,7 @@ struct xe_ggtt {
/** @lock: Mutex lock to protect GGTT data */
struct mutex lock;
/**
- * @gsm: The iomem pointer to the actual location of the translation
+ * @gsm: The iomem pointer to the actual location of the translation
* table located in the GSM for easy PTE manipulation
*/
u64 __iomem *gsm;
diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c
index afd8cc7bd231c..ab501513d806c 100644
--- a/drivers/gpu/drm/xe/xe_guc_submit.c
+++ b/drivers/gpu/drm/xe/xe_guc_submit.c
@@ -408,46 +408,43 @@ void xe_guc_submit_disable(struct xe_guc *guc)
guc->submission_state.enabled = false;
}
-static void __release_guc_id(struct xe_guc *guc, struct xe_exec_queue *q, u32 xa_count)
+static void __release_guc_id(struct xe_guc *guc, struct xe_exec_queue *q,
+ int count)
{
int i;
- lockdep_assert_held(&guc->submission_state.lock);
+ mutex_lock(&guc->submission_state.lock);
- for (i = 0; i < xa_count; ++i)
- xa_erase(&guc->submission_state.exec_queue_lookup, q->guc->id + i);
+ for (i = 0; i < count; ++i)
+ xa_erase(&guc->submission_state.exec_queue_lookup,
+ q->guc->id + i);
xe_guc_id_mgr_release_locked(&guc->submission_state.idm,
q->guc->id, q->width);
if (xa_empty(&guc->submission_state.exec_queue_lookup))
wake_up(&guc->submission_state.fini_wq);
+
+ mutex_unlock(&guc->submission_state.lock);
}
static int alloc_guc_id(struct xe_guc *guc, struct xe_exec_queue *q)
{
- int ret;
- int i;
-
- /*
- * Must use GFP_NOWAIT as this lock is in the dma fence signalling path,
- * worse case user gets -ENOMEM on engine create and has to try again.
- *
- * FIXME: Have caller pre-alloc or post-alloc /w GFP_KERNEL to prevent
- * failure.
- */
- lockdep_assert_held(&guc->submission_state.lock);
+ int ret, i;
+ mutex_lock(&guc->submission_state.lock);
ret = xe_guc_id_mgr_reserve_locked(&guc->submission_state.idm,
q->width);
+ mutex_unlock(&guc->submission_state.lock);
if (ret < 0)
return ret;
q->guc->id = ret;
+ /* Reserve empty slots. */
for (i = 0; i < q->width; ++i) {
- ret = xa_err(xa_store(&guc->submission_state.exec_queue_lookup,
- q->guc->id + i, q, GFP_NOWAIT));
+ ret = xa_insert(&guc->submission_state.exec_queue_lookup,
+ q->guc->id + i, NULL, GFP_KERNEL);
if (ret)
goto err_release;
}
@@ -460,11 +457,24 @@ err_release:
return ret;
}
+static void publish_guc_id(struct xe_guc *guc, struct xe_exec_queue *q)
+{
+ int i;
+
+ lockdep_assert_held(&guc->submission_state.lock);
+
+ for (i = 0; i < q->width; ++i) {
+ void *old;
+
+ old = xa_store(&guc->submission_state.exec_queue_lookup,
+ q->guc->id + i, q, GFP_NOWAIT);
+ XE_WARN_ON(old || xa_is_err(old));
+ }
+}
+
static void release_guc_id(struct xe_guc *guc, struct xe_exec_queue *q)
{
- mutex_lock(&guc->submission_state.lock);
__release_guc_id(guc, q, q->width);
- mutex_unlock(&guc->submission_state.lock);
}
struct exec_queue_policy {
@@ -1961,6 +1971,12 @@ static int guc_exec_queue_init(struct xe_exec_queue *q)
timeout = (q->vm && xe_vm_in_lr_mode(q->vm)) ? MAX_SCHEDULE_TIMEOUT :
msecs_to_jiffies(q->sched_props.job_timeout_ms);
+ err = alloc_guc_id(guc, q);
+ if (err)
+ goto err_free;
+
+ xe_exec_queue_assign_name(q, q->guc->id);
+
/*
* Use primary queue's submit_wq for all secondary queues of a
* multi queue group. This serialization avoids any locking around
@@ -1977,28 +1993,21 @@ static int guc_exec_queue_init(struct xe_exec_queue *q)
timeout, guc_to_gt(guc)->ordered_wq, NULL,
q->name, gt_to_xe(q->gt)->drm.dev);
if (err)
- goto err_free;
+ goto err_release_id;
sched = &ge->sched;
err = xe_sched_entity_init(&ge->entity, sched);
if (err)
goto err_sched;
- mutex_lock(&guc->submission_state.lock);
-
- err = alloc_guc_id(guc, q);
- if (err)
- goto err_entity;
-
q->entity = &ge->entity;
+ mutex_lock(&guc->submission_state.lock);
if (xe_guc_read_stopped(guc) || vf_recovery(guc))
xe_sched_stop(sched);
-
+ publish_guc_id(guc, q);
mutex_unlock(&guc->submission_state.lock);
- xe_exec_queue_assign_name(q, q->guc->id);
-
/*
* Maintain secondary queues of the multi queue group in a list
* for handling dependencies across the queues in the group.
@@ -2021,11 +2030,10 @@ static int guc_exec_queue_init(struct xe_exec_queue *q)
return 0;
-err_entity:
- mutex_unlock(&guc->submission_state.lock);
- xe_sched_entity_fini(&ge->entity);
err_sched:
xe_sched_fini(&ge->sched);
+err_release_id:
+ release_guc_id(guc, q);
err_free:
kfree(ge);
diff --git a/drivers/gpu/drm/xe/xe_late_bind_fw_types.h b/drivers/gpu/drm/xe/xe_late_bind_fw_types.h
index 7fdb24e810b3c..ee5efe60774ea 100644
--- a/drivers/gpu/drm/xe/xe_late_bind_fw_types.h
+++ b/drivers/gpu/drm/xe/xe_late_bind_fw_types.h
@@ -10,7 +10,8 @@
#include <linux/mutex.h>
#include <linux/types.h>
#include <linux/workqueue.h>
-#include "xe_uc_fw_abi.h"
+
+#include "abi/uc_fw_abi.h"
#define XE_LB_MAX_PAYLOAD_SIZE SZ_4K
diff --git a/drivers/gpu/drm/xe/xe_oa.c b/drivers/gpu/drm/xe/xe_oa.c
index 4bf4b1f65929f..9fbd21b0ef974 100644
--- a/drivers/gpu/drm/xe/xe_oa.c
+++ b/drivers/gpu/drm/xe/xe_oa.c
@@ -1698,11 +1698,12 @@ static int xe_oa_release(struct inode *inode, struct file *file)
static int xe_oa_mmap(struct file *file, struct vm_area_struct *vma)
{
struct xe_oa_stream *stream = file->private_data;
+ int ret = xe_observation_paranoid_check();
struct xe_bo *bo = stream->oa_buffer.bo;
- if (xe_observation_paranoid && !perfmon_capable()) {
+ if (ret) {
drm_dbg(&stream->oa->xe->drm, "Insufficient privilege to map OA buffer\n");
- return -EACCES;
+ return ret;
}
/* Can mmap the entire OA buffer or nothing (no partial OA buffer mmaps) */
@@ -2073,10 +2074,12 @@ int xe_oa_stream_open_ioctl(struct drm_device *dev, u64 data, struct drm_file *f
privileged_op = true;
}
- if (privileged_op && xe_observation_paranoid && !perfmon_capable()) {
- drm_dbg(&oa->xe->drm, "Insufficient privileges to open xe OA stream\n");
- ret = -EACCES;
- goto err_exec_q;
+ if (privileged_op) {
+ ret = xe_observation_paranoid_check();
+ if (ret) {
+ drm_dbg(&oa->xe->drm, "Insufficient privileges to open xe OA stream\n");
+ goto err_exec_q;
+ }
}
if (!param.exec_q && !param.sample) {
@@ -2358,9 +2361,10 @@ int xe_oa_add_config_ioctl(struct drm_device *dev, u64 data, struct drm_file *fi
return -ENODEV;
}
- if (xe_observation_paranoid && !perfmon_capable()) {
+ err = xe_observation_paranoid_check();
+ if (err) {
drm_dbg(&oa->xe->drm, "Insufficient privileges to add xe OA config\n");
- return -EACCES;
+ return err;
}
err = copy_from_user(&param, u64_to_user_ptr(data), sizeof(param));
@@ -2460,9 +2464,10 @@ int xe_oa_remove_config_ioctl(struct drm_device *dev, u64 data, struct drm_file
return -ENODEV;
}
- if (xe_observation_paranoid && !perfmon_capable()) {
+ ret = xe_observation_paranoid_check();
+ if (ret) {
drm_dbg(&oa->xe->drm, "Insufficient privileges to remove xe OA config\n");
- return -EACCES;
+ return ret;
}
ret = get_user(arg, ptr);
diff --git a/drivers/gpu/drm/xe/xe_observation.c b/drivers/gpu/drm/xe/xe_observation.c
index e3f9b546207e4..39e05b9131a74 100644
--- a/drivers/gpu/drm/xe/xe_observation.c
+++ b/drivers/gpu/drm/xe/xe_observation.c
@@ -4,6 +4,7 @@
*/
#include <linux/errno.h>
+#include <linux/perf_event.h>
#include <linux/sysctl.h>
#include <uapi/drm/xe_drm.h>
@@ -12,9 +13,28 @@
#include "xe_oa.h"
#include "xe_observation.h"
-u32 xe_observation_paranoid = true;
+static u32 xe_observation_paranoid = true;
static struct ctl_table_header *sysctl_header;
+/**
+ * xe_observation_paranoid_check - Gate access to xe observation streams.
+ *
+ * When the xe-specific observation_paranoid sysctl is enabled (the
+ * default), defer to perf_allow_cpu() so that access is governed by the
+ * same policy as system-wide perf CPU events: kernel.perf_event_paranoid
+ * plus the security_perf_event_open() LSM hook. When the sysctl has been
+ * cleared by a privileged user, observation is open to all callers.
+ *
+ * Return: 0 if access is permitted, a negative errno otherwise.
+ */
+int xe_observation_paranoid_check(void)
+{
+ if (!xe_observation_paranoid)
+ return 0;
+
+ return perf_allow_cpu();
+}
+
static int xe_oa_ioctl(struct drm_device *dev, struct drm_xe_observation_param *arg,
struct drm_file *file)
{
@@ -83,11 +103,13 @@ static const struct ctl_table observation_ctl_table[] = {
};
/**
- * xe_observation_sysctl_register - Register xe_observation_paranoid sysctl
+ * xe_observation_sysctl_register - Register the observation_paranoid sysctl
*
- * Normally only superuser/root can access observation stream
- * data. However, superuser can set xe_observation_paranoid sysctl to 0 to
- * allow non-privileged users to also access observation data.
+ * When dev.xe.observation_paranoid is set (the default), access to
+ * observation streams follows the system-wide perf_allow_cpu() policy:
+ * kernel.perf_event_paranoid plus the security_perf_event_open() LSM
+ * hook. A privileged user can clear the sysctl to bypass that gate and
+ * allow unprivileged access to observation data.
*
* Return: always returns 0
*/
diff --git a/drivers/gpu/drm/xe/xe_observation.h b/drivers/gpu/drm/xe/xe_observation.h
index 17816998e9666..73a03e03c96a7 100644
--- a/drivers/gpu/drm/xe/xe_observation.h
+++ b/drivers/gpu/drm/xe/xe_observation.h
@@ -11,8 +11,7 @@
struct drm_device;
struct drm_file;
-extern u32 xe_observation_paranoid;
-
+int xe_observation_paranoid_check(void);
int xe_observation_ioctl(struct drm_device *dev, void *data, struct drm_file *file);
int xe_observation_sysctl_register(void);
void xe_observation_sysctl_unregister(void);
diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c
index 1243c7d8ed10a..3165686e3e04b 100644
--- a/drivers/gpu/drm/xe/xe_pci.c
+++ b/drivers/gpu/drm/xe/xe_pci.c
@@ -575,14 +575,14 @@ static bool id_blocked(u16 device_id)
}
static const struct xe_subplatform_desc *
-find_subplatform(const struct xe_device *xe, const struct xe_device_desc *desc)
+find_subplatform(const struct xe_device_desc *desc, u16 devid)
{
const struct xe_subplatform_desc *sp;
const u16 *id;
for (sp = desc->subplatforms; sp && sp->subplatform; sp++)
for (id = sp->pciidlist; *id; id++)
- if (*id == xe->info.devid)
+ if (*id == devid)
return sp;
return NULL;
@@ -726,6 +726,16 @@ static int handle_gmdid(struct xe_device *xe,
return 0;
}
+static void init_devid(struct xe_device *xe)
+{
+ struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
+
+ KUNIT_STATIC_STUB_REDIRECT(init_devid, xe);
+
+ xe->info.devid = pdev->device;
+ xe->info.revid = pdev->revision;
+}
+
/*
* Initialize device info content that only depends on static driver_data
* passed to the driver at probe time from PCI ID table.
@@ -741,6 +751,8 @@ static int xe_info_init_early(struct xe_device *xe,
xe->info.subplatform = subplatform_desc ?
subplatform_desc->subplatform : XE_SUBPLATFORM_NONE;
+ init_devid(xe);
+
xe->info.dma_mask_size = desc->dma_mask_size;
xe->info.va_bits = desc->va_bits;
xe->info.vm_max_level = desc->vm_max_level;
@@ -777,6 +789,7 @@ static int xe_info_init_early(struct xe_device *xe,
xe->info.probe_display = IS_ENABLED(CONFIG_DRM_XE_DISPLAY) &&
xe_modparam.probe_display &&
desc->has_display;
+ xe->info.force_execlist = xe_modparam.force_execlist;
xe_assert(xe, desc->max_gt_per_tile > 0);
xe_assert(xe, desc->max_gt_per_tile <= XE_MAX_GT_PER_TILE);
@@ -1064,6 +1077,8 @@ static int xe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct xe_device *xe;
int err;
+ subplatform_desc = find_subplatform(desc, pdev->device);
+
xe_configfs_check_device(pdev);
if (desc->require_force_probe && !id_forced(pdev->device)) {
@@ -1091,14 +1106,13 @@ static int xe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
return err;
- xe = xe_device_create(pdev, ent);
+ xe = xe_device_create(pdev);
if (IS_ERR(xe))
return PTR_ERR(xe);
pci_set_drvdata(pdev, &xe->drm);
xe_pm_assert_unbounded_bridge(xe);
- subplatform_desc = find_subplatform(xe, desc);
pci_set_master(pdev);
@@ -1153,7 +1167,7 @@ static int xe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
str_yes_no(xe_device_has_sriov(xe)),
xe_sriov_mode_to_string(xe_device_sriov_mode(xe)));
- err = xe_pm_init_early(xe);
+ err = xe_pm_probe(xe);
if (err)
return err;
@@ -1165,9 +1179,6 @@ static int xe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
goto err_driver_cleanup;
- drm_dbg(&xe->drm, "d3cold: capable=%s\n",
- str_yes_no(xe->d3cold.capable));
-
return 0;
err_driver_cleanup:
diff --git a/drivers/gpu/drm/xe/xe_pm.c b/drivers/gpu/drm/xe/xe_pm.c
index d4672eb074762..99562f691080b 100644
--- a/drivers/gpu/drm/xe/xe_pm.c
+++ b/drivers/gpu/drm/xe/xe_pm.c
@@ -24,6 +24,7 @@
#include "xe_irq.h"
#include "xe_late_bind_fw.h"
#include "xe_pcode.h"
+#include "xe_printk.h"
#include "xe_pxp.h"
#include "xe_sriov_vf_ccs.h"
#include "xe_sysctrl.h"
@@ -349,10 +350,22 @@ static void xe_pm_runtime_init(struct xe_device *xe)
pm_runtime_put(dev);
}
+/**
+ * xe_pm_init_early() - Initialize Xe Power Management
+ * @xe: the &xe_device instance
+ *
+ * Initialize everything that is a "software-only" state that does not
+ * require access to any of the device's hardware data.
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
int xe_pm_init_early(struct xe_device *xe)
{
int err;
+ init_completion(&xe->pm_block);
+ complete_all(&xe->pm_block);
+ INIT_LIST_HEAD(&xe->rebind_resume_list);
INIT_LIST_HEAD(&xe->mem_access.vram_userfault.list);
err = drmm_mutex_init(&xe->drm, &xe->mem_access.vram_userfault.lock);
@@ -363,11 +376,30 @@ int xe_pm_init_early(struct xe_device *xe)
if (err)
return err;
- xe->d3cold.capable = xe_pm_pci_d3cold_capable(xe);
+ err = drmm_mutex_init(&xe->drm, &xe->rebind_resume_lock);
+ if (err)
+ return err;
+
return 0;
}
ALLOW_ERROR_INJECTION(xe_pm_init_early, ERRNO); /* See xe_pci_probe() */
+/**
+ * xe_pm_probe() - Initialize Xe Power Management
+ * @xe: the &xe_device instance
+ *
+ * Check d3cold capability.
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int xe_pm_probe(struct xe_device *xe)
+{
+ xe->d3cold.capable = xe_pm_pci_d3cold_capable(xe);
+ xe_dbg(xe, "d3cold: capable=%s\n", str_yes_no(xe->d3cold.capable));
+
+ return 0;
+}
+
static u32 vram_threshold_value(struct xe_device *xe)
{
if (xe->info.platform == XE_BATTLEMAGE) {
@@ -459,14 +491,6 @@ int xe_pm_init(struct xe_device *xe)
if (err)
return err;
- err = drmm_mutex_init(&xe->drm, &xe->rebind_resume_lock);
- if (err)
- goto err_unregister;
-
- init_completion(&xe->pm_block);
- complete_all(&xe->pm_block);
- INIT_LIST_HEAD(&xe->rebind_resume_list);
-
/* For now suspend/resume is only allowed with GuC */
if (!xe_device_uc_enabled(xe))
return 0;
diff --git a/drivers/gpu/drm/xe/xe_pm.h b/drivers/gpu/drm/xe/xe_pm.h
index 6b27039e7b2d7..6d5ab09cb7696 100644
--- a/drivers/gpu/drm/xe/xe_pm.h
+++ b/drivers/gpu/drm/xe/xe_pm.h
@@ -17,6 +17,7 @@ int xe_pm_suspend(struct xe_device *xe);
int xe_pm_resume(struct xe_device *xe);
int xe_pm_init_early(struct xe_device *xe);
+int xe_pm_probe(struct xe_device *xe);
int xe_pm_init(struct xe_device *xe);
void xe_pm_fini(struct xe_device *xe);
bool xe_pm_runtime_suspended(struct xe_device *xe);
diff --git a/drivers/gpu/drm/xe/xe_rtp.c b/drivers/gpu/drm/xe/xe_rtp.c
index 1a4dcbbbc1764..dec9d94e6fb0c 100644
--- a/drivers/gpu/drm/xe/xe_rtp.c
+++ b/drivers/gpu/drm/xe/xe_rtp.c
@@ -30,146 +30,199 @@ static bool has_samedia(const struct xe_device *xe)
return xe->info.media_verx100 >= 1300;
}
-static bool rule_matches(const struct xe_device *xe,
- struct xe_gt *gt,
- struct xe_hw_engine *hwe,
- const struct xe_rtp_rule *rules,
- unsigned int n_rules)
+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_rtp_rule *r;
- unsigned int i, rcount = 0;
- bool match;
+ 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;
+ case XE_RTP_MATCH_SUBPLATFORM:
+ return xe->info.platform == r->platform &&
+ xe->info.subplatform == r->subplatform;
+ case XE_RTP_MATCH_PLATFORM_STEP:
+ if (drm_WARN_ON(&xe->drm, xe->info.step.platform == STEP_NONE))
+ return false;
+
+ return xe->info.step.platform >= r->step_start &&
+ xe->info.step.platform < r->step_end;
+ case XE_RTP_MATCH_GRAPHICS_VERSION:
+ if (drm_WARN_ON(&xe->drm, !gt))
+ return false;
- for (r = rules, i = 0; i < n_rules; r = &rules[++i]) {
- switch (r->match_type) {
- case XE_RTP_MATCH_OR:
- /*
- * This is only reached if a complete set of
- * rules passed or none were evaluated. For both cases,
- * shortcut the other rules and return the proper value.
- */
- goto done;
- case XE_RTP_MATCH_PLATFORM:
- match = xe->info.platform == r->platform;
- break;
- case XE_RTP_MATCH_SUBPLATFORM:
- match = xe->info.platform == r->platform &&
- xe->info.subplatform == r->subplatform;
- break;
- case XE_RTP_MATCH_PLATFORM_STEP:
- if (drm_WARN_ON(&xe->drm, xe->info.step.platform == STEP_NONE))
- return false;
+ return xe->info.graphics_verx100 == r->ver_start &&
+ (!has_samedia(xe) || !xe_gt_is_media_type(gt));
+ case XE_RTP_MATCH_GRAPHICS_VERSION_RANGE:
+ if (drm_WARN_ON(&xe->drm, !gt))
+ return false;
- match = xe->info.step.platform >= r->step_start &&
- xe->info.step.platform < r->step_end;
- break;
- case XE_RTP_MATCH_GRAPHICS_VERSION:
- if (drm_WARN_ON(&xe->drm, !gt))
- return false;
+ return xe->info.graphics_verx100 >= r->ver_start &&
+ xe->info.graphics_verx100 <= r->ver_end &&
+ (!has_samedia(xe) || !xe_gt_is_media_type(gt));
+ case XE_RTP_MATCH_GRAPHICS_VERSION_ANY_GT:
+ if (drm_WARN_ON(&xe->drm, !gt))
+ return false;
- match = xe->info.graphics_verx100 == r->ver_start &&
- (!has_samedia(xe) || !xe_gt_is_media_type(gt));
- break;
- case XE_RTP_MATCH_GRAPHICS_VERSION_RANGE:
- if (drm_WARN_ON(&xe->drm, !gt))
- return false;
+ return xe->info.graphics_verx100 == r->ver_start;
+ case XE_RTP_MATCH_GRAPHICS_STEP:
+ if (drm_WARN_ON(&xe->drm, !gt))
+ return false;
- match = xe->info.graphics_verx100 >= r->ver_start &&
- xe->info.graphics_verx100 <= r->ver_end &&
- (!has_samedia(xe) || !xe_gt_is_media_type(gt));
- break;
- case XE_RTP_MATCH_GRAPHICS_VERSION_ANY_GT:
- if (drm_WARN_ON(&xe->drm, !gt))
- return false;
+ return xe->info.step.graphics >= r->step_start &&
+ xe->info.step.graphics < r->step_end &&
+ (!has_samedia(xe) || !xe_gt_is_media_type(gt));
+ case XE_RTP_MATCH_MEDIA_VERSION:
+ if (drm_WARN_ON(&xe->drm, !gt))
+ return false;
- match = xe->info.graphics_verx100 == r->ver_start;
- break;
- case XE_RTP_MATCH_GRAPHICS_STEP:
- if (drm_WARN_ON(&xe->drm, !gt))
- return false;
+ return xe->info.media_verx100 == r->ver_start &&
+ (!has_samedia(xe) || xe_gt_is_media_type(gt));
+ case XE_RTP_MATCH_MEDIA_VERSION_RANGE:
+ if (drm_WARN_ON(&xe->drm, !gt))
+ return false;
- match = xe->info.step.graphics >= r->step_start &&
- xe->info.step.graphics < r->step_end &&
- (!has_samedia(xe) || !xe_gt_is_media_type(gt));
- break;
- case XE_RTP_MATCH_MEDIA_VERSION:
- if (drm_WARN_ON(&xe->drm, !gt))
- return false;
+ return xe->info.media_verx100 >= r->ver_start &&
+ xe->info.media_verx100 <= r->ver_end &&
+ (!has_samedia(xe) || xe_gt_is_media_type(gt));
+ case XE_RTP_MATCH_MEDIA_STEP:
+ if (drm_WARN_ON(&xe->drm, !gt))
+ return false;
- match = xe->info.media_verx100 == r->ver_start &&
- (!has_samedia(xe) || xe_gt_is_media_type(gt));
- break;
- case XE_RTP_MATCH_MEDIA_VERSION_RANGE:
- if (drm_WARN_ON(&xe->drm, !gt))
- return false;
+ return xe->info.step.media >= r->step_start &&
+ xe->info.step.media < r->step_end &&
+ (!has_samedia(xe) || xe_gt_is_media_type(gt));
+ case XE_RTP_MATCH_MEDIA_VERSION_ANY_GT:
+ if (drm_WARN_ON(&xe->drm, !gt))
+ return false;
- match = xe->info.media_verx100 >= r->ver_start &&
- xe->info.media_verx100 <= r->ver_end &&
- (!has_samedia(xe) || xe_gt_is_media_type(gt));
- break;
- case XE_RTP_MATCH_MEDIA_STEP:
- if (drm_WARN_ON(&xe->drm, !gt))
- return false;
+ return xe->info.media_verx100 == r->ver_start;
+ case XE_RTP_MATCH_INTEGRATED:
+ return !xe->info.is_dgfx;
+ case XE_RTP_MATCH_DISCRETE:
+ return xe->info.is_dgfx;
+ case XE_RTP_MATCH_ENGINE_CLASS:
+ if (drm_WARN_ON(&xe->drm, !hwe))
+ return false;
- match = xe->info.step.media >= r->step_start &&
- xe->info.step.media < r->step_end &&
- (!has_samedia(xe) || xe_gt_is_media_type(gt));
- break;
- case XE_RTP_MATCH_MEDIA_VERSION_ANY_GT:
- if (drm_WARN_ON(&xe->drm, !gt))
- return false;
+ return hwe->class == r->engine_class;
+ case XE_RTP_MATCH_NOT_ENGINE_CLASS:
+ if (drm_WARN_ON(&xe->drm, !hwe))
+ return false;
- match = xe->info.media_verx100 == r->ver_start;
- break;
- case XE_RTP_MATCH_INTEGRATED:
- match = !xe->info.is_dgfx;
- break;
- case XE_RTP_MATCH_DISCRETE:
- match = xe->info.is_dgfx;
- break;
- case XE_RTP_MATCH_ENGINE_CLASS:
- if (drm_WARN_ON(&xe->drm, !hwe))
- return false;
+ return hwe->class != r->engine_class;
+ case XE_RTP_MATCH_FUNC:
+ return r->match_func(xe, gt, hwe);
+ default:
+ drm_warn(&xe->drm, "Invalid RTP match %u\n",
+ r->match_type);
+ return false;
+ }
+}
- match = hwe->class == r->engine_class;
- break;
- case XE_RTP_MATCH_NOT_ENGINE_CLASS:
- if (drm_WARN_ON(&xe->drm, !hwe))
- return false;
+/*
+ * 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;
- match = hwe->class != r->engine_class;
- break;
- case XE_RTP_MATCH_FUNC:
- match = r->match_func(xe, gt, hwe);
- break;
- default:
- drm_warn(&xe->drm, "Invalid RTP match %u\n",
- r->match_type);
+ 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;
- }
+ }
- if (!match) {
- /*
- * 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)
- ;
+ return match;
+}
- if (i >= n_rules)
- return false;
+/*
+ * 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);
- rcount = 0;
- } else {
- rcount++;
- }
+ 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);
}
-done:
- if (drm_WARN_ON(&xe->drm, !rcount))
- return false;
+ return match;
+}
- return true;
+static bool rule_matches_with_err(const struct xe_device *xe,
+ struct xe_gt *gt,
+ struct xe_hw_engine *hwe,
+ const struct xe_rtp_rule *rules,
+ unsigned int n_rules,
+ int *err)
+{
+ 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 = match_ctx.err;
+
+ return match;
+}
+
+static bool rule_matches(const struct xe_device *xe,
+ struct xe_gt *gt,
+ struct xe_hw_engine *hwe,
+ const struct xe_rtp_rule *rules,
+ unsigned int n_rules)
+{
+ return rule_matches_with_err(xe, gt, hwe, rules, n_rules, NULL);
}
static void rtp_add_sr_entry(const struct xe_rtp_action *action,
@@ -412,3 +465,7 @@ bool xe_rtp_match_has_msix(const struct xe_device *xe,
{
return xe_device_has_msix(xe);
}
+
+#if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST)
+#include "tests/xe_rtp.c"
+#endif
diff --git a/drivers/gpu/drm/xe/xe_rtp.h b/drivers/gpu/drm/xe/xe_rtp.h
index 562082b18d7b8..e4f1930ca1c3a 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))
+ * ...
+ * },
* ...
* };
*/
diff --git a/drivers/gpu/drm/xe/xe_uc_fw.h b/drivers/gpu/drm/xe/xe_uc_fw.h
index bb281b72a6772..f2d3a3e7208bc 100644
--- a/drivers/gpu/drm/xe/xe_uc_fw.h
+++ b/drivers/gpu/drm/xe/xe_uc_fw.h
@@ -8,8 +8,8 @@
#include <linux/errno.h>
+#include "abi/uc_fw_abi.h"
#include "xe_macros.h"
-#include "xe_uc_fw_abi.h"
#include "xe_uc_fw_types.h"
struct drm_printer;
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 48d851fbd8ea5..5842552294c19 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -1791,22 +1791,8 @@ static inline int perf_is_paranoid(void)
}
extern int perf_allow_kernel(void);
-
-static inline int perf_allow_cpu(void)
-{
- if (sysctl_perf_event_paranoid > 0 && !perfmon_capable())
- return -EACCES;
-
- return security_perf_event_open(PERF_SECURITY_CPU);
-}
-
-static inline int perf_allow_tracepoint(void)
-{
- if (sysctl_perf_event_paranoid > -1 && !perfmon_capable())
- return -EPERM;
-
- return security_perf_event_open(PERF_SECURITY_TRACEPOINT);
-}
+extern int perf_allow_cpu(void);
+extern int perf_allow_tracepoint(void);
extern int perf_exclude_event(struct perf_event *event, struct pt_regs *regs);
@@ -2023,6 +2009,19 @@ perf_event_pause(struct perf_event *event, bool reset) { return 0; }
static inline int
perf_exclude_event(struct perf_event *event, struct pt_regs *regs) { return 0; }
+static inline int perf_allow_kernel(void)
+{
+ return perfmon_capable() ? 0 : -EACCES;
+}
+static inline int perf_allow_cpu(void)
+{
+ return perfmon_capable() ? 0 : -EACCES;
+}
+static inline int perf_allow_tracepoint(void)
+{
+ return perfmon_capable() ? 0 : -EPERM;
+}
+
#endif /* !CONFIG_PERF_EVENTS */
#if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_INTEL)
diff --git a/kernel/events/core.c b/kernel/events/core.c
index bcaf175f3ded2..81530f5d13a6b 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -14740,6 +14740,24 @@ int perf_allow_kernel(void)
}
EXPORT_SYMBOL_GPL(perf_allow_kernel);
+int perf_allow_cpu(void)
+{
+ if (sysctl_perf_event_paranoid > 0 && !perfmon_capable())
+ return -EACCES;
+
+ return security_perf_event_open(PERF_SECURITY_CPU);
+}
+EXPORT_SYMBOL_GPL(perf_allow_cpu);
+
+int perf_allow_tracepoint(void)
+{
+ if (sysctl_perf_event_paranoid > -1 && !perfmon_capable())
+ return -EPERM;
+
+ return security_perf_event_open(PERF_SECURITY_TRACEPOINT);
+}
+EXPORT_SYMBOL_GPL(perf_allow_tracepoint);
+
/*
* Inherit an event from parent task to child task.
*