mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
Driver Changes:
- drm/xe: Move xe_uc_fw_abi.h to abi/ (Michal Wajdeczko) - drm/xe: Restore IDLEDLY regiter on engine reset (Balasubramani Vivekanandan) - drm/xe/pm: Do early initialization in init_early() (Michal Wajdeczko) - drm/xe/pm: Don't access device in init_early() (Michal Wajdeczko) - drm/xe: Separate early xe_device initialization (Michal Wajdeczko) - drm/xe: Move xe->info.devid|revid initialization (Michal Wajdeczko) - drm/xe: Move xe->info.force_execlist initialization (Michal Wajdeczko) - drm/xe: Drop unused param from xe_device_create() (Michal Wajdeczko) - drm/xe: Use raw device ID to find sub-platform descriptor (Michal Wajdeczko) - drm/xe: Assign queue name in time for drm_sched_init (Tvrtko Ursulin) - drm/xe/rtp: Implement a structured parser for rule matching (Gustavo Sousa) - drm/xe/rtp: Fully parse the ruleset (Gustavo Sousa) - drm/xe/rtp: Extract rule_match_item() (Gustavo Sousa) - drm/xe/rtp: Do not break parsing when missing context (Gustavo Sousa) - drm/xe/rtp: Don't short-circuit to false in or-yes case (Gustavo Sousa) - drm/xe/rtp: Drop rule matching cases from rtp_to_sr_cases and rtp_cases (Gustavo Sousa) - drm/xe/rtp: Write kunit test cases specific for rule matching (Gustavo Sousa) -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQRskUM7w1oG5rx2IZO4FpNVCsYGvwUCahg6XQAKCRC4FpNVCsYG v1tjAP9yDWHxY1ZLkfg3boEWRrWy5HidWRYXRPEcHFZy9asj9QD/YtTu+ZBEVQuY p4pyZSYwgDQYFSQI7ajF2yWj2P1KWgs= =njjy -----END PGP SIGNATURE----- Merge tag 'drm-xe-next-2026-05-28' of https://gitlab.freedesktop.org/drm/xe/kernel into drm-next Driver Changes: - drm/xe: Move xe_uc_fw_abi.h to abi/ (Michal Wajdeczko) - drm/xe: Restore IDLEDLY regiter on engine reset (Balasubramani Vivekanandan) - drm/xe/pm: Do early initialization in init_early() (Michal Wajdeczko) - drm/xe/pm: Don't access device in init_early() (Michal Wajdeczko) - drm/xe: Separate early xe_device initialization (Michal Wajdeczko) - drm/xe: Move xe->info.devid|revid initialization (Michal Wajdeczko) - drm/xe: Move xe->info.force_execlist initialization (Michal Wajdeczko) - drm/xe: Drop unused param from xe_device_create() (Michal Wajdeczko) - drm/xe: Use raw device ID to find sub-platform descriptor (Michal Wajdeczko) - drm/xe: Assign queue name in time for drm_sched_init (Tvrtko Ursulin) - drm/xe/rtp: Implement a structured parser for rule matching (Gustavo Sousa) - drm/xe/rtp: Fully parse the ruleset (Gustavo Sousa) - drm/xe/rtp: Extract rule_match_item() (Gustavo Sousa) - drm/xe/rtp: Do not break parsing when missing context (Gustavo Sousa) - drm/xe/rtp: Don't short-circuit to false in or-yes case (Gustavo Sousa) - drm/xe/rtp: Drop rule matching cases from rtp_to_sr_cases and rtp_cases (Gustavo Sousa) - drm/xe/rtp: Write kunit test cases specific for rule matching (Gustavo Sousa) Signed-off-by: Dave Airlie <airlied@redhat.com> From: Thomas Hellstrom <thomas.hellstrom@linux.intel.com> Link: https://patch.msgid.link/ahg7tgWh8djEngjM@fedora
This commit is contained in:
commit
5ebf57fb7c
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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 @@ int xe_pci_fake_device_init(struct xe_device *xe)
|
|||
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);
|
||||
|
|
|
|||
38
drivers/gpu/drm/xe/tests/xe_rtp.c
Normal file
38
drivers/gpu/drm/xe/tests/xe_rtp.c
Normal file
|
|
@ -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);
|
||||
|
|
@ -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",
|
||||
|
|
@ -124,80 +321,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,
|
||||
|
|
@ -458,16 +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("r2"),
|
||||
XE_RTP_RULES(FUNC(match_yes)),
|
||||
},
|
||||
{ XE_RTP_NAME("r3"),
|
||||
XE_RTP_RULES(FUNC(match_no)),
|
||||
},
|
||||
|
|
@ -475,50 +597,15 @@ static const struct rtp_test_case rtp_cases[] = {
|
|||
},
|
||||
},
|
||||
{
|
||||
.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_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)),
|
||||
},
|
||||
{}
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = "inactive-last_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_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",
|
||||
.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_no)) },
|
||||
{ XE_RTP_NAME("r2"),
|
||||
XE_RTP_RULES(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),
|
||||
{}
|
||||
|
|
|
|||
23
drivers/gpu/drm/xe/tests/xe_rtp_test.h
Normal file
23
drivers/gpu/drm/xe/tests/xe_rtp_test.h
Normal file
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -768,6 +768,11 @@ static unsigned int guc_mmio_regset_write(struct xe_guc_ads *ads,
|
|||
}
|
||||
}
|
||||
|
||||
if (XE_GT_WA(hwe->gt, 16023105232))
|
||||
guc_mmio_regset_write_one(ads, regset_map,
|
||||
RING_IDLEDLY(hwe->mmio_base),
|
||||
count++);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 @@ static int alloc_guc_id(struct xe_guc *guc, struct xe_exec_queue *q)
|
|||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -30,146 +30,199 @@ static bool has_samedia(const struct xe_device *xe)
|
|||
return xe->info.media_verx100 >= 1300;
|
||||
}
|
||||
|
||||
struct rule_match_ctx {
|
||||
const struct xe_device *xe;
|
||||
struct xe_gt *gt;
|
||||
struct xe_hw_engine *hwe;
|
||||
const struct xe_rtp_rule *rules;
|
||||
const unsigned int n_rules;
|
||||
unsigned int head;
|
||||
int err;
|
||||
};
|
||||
|
||||
static bool rule_is_item(const struct xe_rtp_rule *r)
|
||||
{
|
||||
return r->match_type != XE_RTP_MATCH_OR;
|
||||
}
|
||||
|
||||
static bool rule_match_item(struct rule_match_ctx *match_ctx)
|
||||
{
|
||||
const struct xe_device *xe = match_ctx->xe;
|
||||
struct xe_gt *gt = match_ctx->gt;
|
||||
struct xe_hw_engine *hwe = match_ctx->hwe;
|
||||
const struct xe_rtp_rule *r = &match_ctx->rules[match_ctx->head];
|
||||
|
||||
switch (r->match_type) {
|
||||
case XE_RTP_MATCH_PLATFORM:
|
||||
return xe->info.platform == r->platform;
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
return xe->info.graphics_verx100 == r->ver_start;
|
||||
case XE_RTP_MATCH_GRAPHICS_STEP:
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
return hwe->class == r->engine_class;
|
||||
case XE_RTP_MATCH_NOT_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 a conjunctive set of rules (rules joined by an implicit "AND").
|
||||
*
|
||||
* Once one item evaluates to false, the remaining items are not evaluated
|
||||
* anymore. Nevetheless, all rules are consumed to allow detecting syntax
|
||||
* errors.
|
||||
*/
|
||||
static bool rule_match_and(struct rule_match_ctx *match_ctx, bool parse_only)
|
||||
{
|
||||
bool match = true;
|
||||
unsigned int count = 0;
|
||||
|
||||
while (match_ctx->head < match_ctx->n_rules &&
|
||||
rule_is_item(&match_ctx->rules[match_ctx->head])) {
|
||||
if (!parse_only)
|
||||
match = rule_match_item(match_ctx);
|
||||
|
||||
if (!match)
|
||||
parse_only = true;
|
||||
|
||||
match_ctx->head++;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (drm_WARN_ON(&match_ctx->xe->drm, !count)) {
|
||||
match_ctx->err = -EINVAL;
|
||||
|
||||
if (!parse_only)
|
||||
match = false;
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
/*
|
||||
* Match a disjunctive set of rules (subset of rules joined by
|
||||
* "XE_RTP_MATCH_OR").
|
||||
*
|
||||
* Once one subset evaluates to true, the remaining items are not evaluated
|
||||
* anymore. Nevetheless, all rules are consumed to allow detecting syntax
|
||||
* errors.
|
||||
*/
|
||||
static bool rule_match_or(struct rule_match_ctx *match_ctx)
|
||||
{
|
||||
bool match = rule_match_and(match_ctx, false);
|
||||
|
||||
while (match_ctx->head < match_ctx->n_rules &&
|
||||
match_ctx->rules[match_ctx->head].match_type == XE_RTP_MATCH_OR) {
|
||||
/* Consume XE_RTP_MATCH_OR. */
|
||||
match_ctx->head++;
|
||||
|
||||
match = rule_match_and(match_ctx, match);
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
static bool rule_matches_with_err(const struct xe_device *xe,
|
||||
struct xe_gt *gt,
|
||||
struct xe_hw_engine *hwe,
|
||||
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)
|
||||
{
|
||||
const struct xe_rtp_rule *r;
|
||||
unsigned int i, rcount = 0;
|
||||
bool match;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
match = xe->info.graphics_verx100 == r->ver_start;
|
||||
break;
|
||||
case XE_RTP_MATCH_GRAPHICS_STEP:
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
match = hwe->class == r->engine_class;
|
||||
break;
|
||||
case XE_RTP_MATCH_NOT_ENGINE_CLASS:
|
||||
if (drm_WARN_ON(&xe->drm, !hwe))
|
||||
return false;
|
||||
|
||||
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);
|
||||
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)
|
||||
;
|
||||
|
||||
if (i >= n_rules)
|
||||
return false;
|
||||
|
||||
rcount = 0;
|
||||
} else {
|
||||
rcount++;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (drm_WARN_ON(&xe->drm, !rcount))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
* ...
|
||||
* },
|
||||
* ...
|
||||
* };
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user