diff options
| author | Mark Brown <broonie@kernel.org> | 2026-05-29 22:42:19 +0100 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-05-29 22:42:19 +0100 |
| commit | 062cbcbe2293138856bd93c7bbf269b1d88ee2ae (patch) | |
| tree | 1086ad305bae999f0a1e0c6b112634fbed9574e3 | |
| parent | 945aebe6ed18f5fd87139baafb7a0f9bace7e2ff (diff) | |
| parent | 41e328c62a5662459dcb49cb995ebd5c13179b39 (diff) | |
| download | linux-next-history-062cbcbe2293138856bd93c7bbf269b1d88ee2ae.tar.gz | |
Merge branch 'drm-xe-next' of https://gitlab.freedesktop.org/drm/xe/kernel.git
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 = ®ular_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(¶m, 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. * |
