From d32bf877c0c3ebc345b444cbe009b3f44f9f8073 Mon Sep 17 00:00:00 2001 From: John Hubbard Date: Wed, 27 May 2026 15:55:06 -0700 Subject: perf/core: out-of-line and export perf_allow_cpu/tracepoint() These helpers are static inline in and reach into sysctl_perf_event_paranoid and security_perf_event_open(), neither of which is itself exported. The perf_allow_* trio is therefore asymmetric: built-in callers can use any of the three, but modular code can only call perf_allow_kernel(). Move both bodies into kernel/events/core.c next to perf_allow_kernel() and export them with EXPORT_SYMBOL_GPL, following the shape of commit 5e9629d0ae97 ("drivers/perf: arm_spe: Use perf_allow_kernel() for permissions"). Existing in-tree callers live in built-in arch and tracing code, so the change is invisible to them. Provide !CONFIG_PERF_EVENTS stubs that fall back to perfmon_capable(), so the helpers stay callable when perf is compiled out. Signed-off-by: John Hubbard Reviewed-by: Ashutosh Dixit Link: https://patch.msgid.link/20260527225507.2044027-2-ashutosh.dixit@intel.com Signed-off-by: Ashutosh Dixit --- include/linux/perf_event.h | 31 +++++++++++++++---------------- kernel/events/core.c | 18 ++++++++++++++++++ 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 48d851fbd8ea..5842552294c1 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 6d1f8bad7e1c..735e502beb96 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -14691,6 +14691,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. * -- cgit v1.2.3 From 6680bf0cb7261b7eb62a7226c6845c5c9ce5a009 Mon Sep 17 00:00:00 2001 From: John Hubbard Date: Wed, 27 May 2026 15:55:07 -0700 Subject: drm/xe: gate observation streams with perf_allow_cpu() xe OA and EU-stall paths open-code a partial copy of the system-wide perf CPU-event permission check: if (xe_observation_paranoid && !perfmon_capable()) return -EACCES; This open-coded check skips two things perf_allow_cpu() handles: the graduated kernel.perf_event_paranoid policy that an administrator may have tuned, and the security_perf_event_open() LSM hook. Introduce xe_observation_paranoid_check() to wrap perf_allow_cpu(), and convert the open-coded sites in xe_oa.c and xe_eu_stall.c. The dev.xe.observation_paranoid sysctl still acts as an escape hatch when cleared. xe observation now consults kernel.perf_event_paranoid and the LSM perf hook on every open. Sites that have already configured an LSM perf policy or tuned the paranoid sysctl will see those settings extend to xe. Signed-off-by: John Hubbard Reviewed-by: Ashutosh Dixit Link: https://patch.msgid.link/20260527225507.2044027-3-ashutosh.dixit@intel.com Signed-off-by: Ashutosh Dixit --- drivers/gpu/drm/xe/xe_eu_stall.c | 5 +++-- drivers/gpu/drm/xe/xe_oa.c | 25 +++++++++++++++---------- drivers/gpu/drm/xe/xe_observation.c | 32 +++++++++++++++++++++++++++----- drivers/gpu/drm/xe/xe_observation.h | 3 +-- 4 files changed, 46 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_eu_stall.c b/drivers/gpu/drm/xe/xe_eu_stall.c index 297be3c42b20..d37770c58c5d 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_oa.c b/drivers/gpu/drm/xe/xe_oa.c index 4bf4b1f65929..9fbd21b0ef97 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 e3f9b546207e..39e05b9131a7 100644 --- a/drivers/gpu/drm/xe/xe_observation.c +++ b/drivers/gpu/drm/xe/xe_observation.c @@ -4,6 +4,7 @@ */ #include +#include #include #include @@ -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 17816998e966..73a03e03c96a 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); -- cgit v1.2.3 From 41e328c62a5662459dcb49cb995ebd5c13179b39 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Wed, 27 May 2026 14:21:54 +0200 Subject: drm/xe/ggtt: Fix xe_ggtt documentation The following error is reported during the htmldocs build: ... Documentation/gpu/xe/xe_mm:22: ../drivers/gpu/drm/xe/xe_ggtt.c:125: ERROR: Unexpected indentation. [docutils] Fix this by adding a blank line before the enumeration. While around correct some invalid spaces. Signed-off-by: Michal Wajdeczko Reviewed-by: Maarten Lankhorst Link: https://patch.msgid.link/20260527122154.22480-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_ggtt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_ggtt.c b/drivers/gpu/drm/xe/xe_ggtt.c index a351c578b170..8ec23862477f 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; -- cgit v1.2.3 From 65b8e0ac86e48cfc9128c04dfc53ea3395d030dd Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Fri, 29 May 2026 12:36:02 -0700 Subject: Revert "drm/xe/nvls: Define GuC firmware for NVL-S" This reverts commit 4e88de313ff4d1c67b644b1f39f9fb4089711b71. The early GuC FW definition meant for our CI branch was accidentally merged to the drm-xe-next branch instead. This GuC FW will never be released to linux-firmware, so we do not want the definition to be available in the mainline Linux codebase. Fixes: 4e88de313ff4 ("drm/xe/nvls: Define GuC firmware for NVL-S") Signed-off-by: Daniele Ceraolo Spurio Cc: Julia Filipchuk Cc: Rodrigo Vivi Cc: Matt Roper Cc: stable@vger.kernel.org # v7.0+ Reviewed-by: Rodrigo Vivi Link: https://patch.msgid.link/20260529193558.185436-11-daniele.ceraolospurio@intel.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_uc_fw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_uc_fw.c b/drivers/gpu/drm/xe/xe_uc_fw.c index df2aa196f6f9..3f08a3b54062 100644 --- a/drivers/gpu/drm/xe/xe_uc_fw.c +++ b/drivers/gpu/drm/xe/xe_uc_fw.c @@ -115,7 +115,6 @@ struct fw_blobs_by_type { #define XE_GT_TYPE_ANY XE_GT_TYPE_UNINITIALIZED #define XE_GUC_FIRMWARE_DEFS(fw_def, mmp_ver, major_ver) \ - fw_def(NOVALAKE_S, GT_TYPE_ANY, mmp_ver(xe, guc, nvl, 70, 55, 4)) \ fw_def(PANTHERLAKE, GT_TYPE_ANY, major_ver(xe, guc, ptl, 70, 54, 0)) \ fw_def(BATTLEMAGE, GT_TYPE_ANY, major_ver(xe, guc, bmg, 70, 54, 0)) \ fw_def(LUNARLAKE, GT_TYPE_ANY, major_ver(xe, guc, lnl, 70, 53, 0)) \ -- cgit v1.2.3 From 459f6a32e3689da6928cadceecf3e3fe4716bcc5 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 29 May 2026 21:59:56 +0200 Subject: drm/xe/pcode: Don't ignore drmm_mutex_init failure The drm_device-managed mutex_init might fail and return an error. Add proper error handling. While around, update the function name to clearly indicate this is an early software-only initialization. Signed-off-by: Michal Wajdeczko Reviewed-by: Rodrigo Vivi Link: https://patch.msgid.link/20260529195956.25349-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_pcode.c | 8 +++++--- drivers/gpu/drm/xe/xe_pcode.h | 2 +- drivers/gpu/drm/xe/xe_tile.c | 4 +++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_pcode.c b/drivers/gpu/drm/xe/xe_pcode.c index dc66d0c7ee06..866986694d9c 100644 --- a/drivers/gpu/drm/xe/xe_pcode.c +++ b/drivers/gpu/drm/xe/xe_pcode.c @@ -323,15 +323,17 @@ int xe_pcode_ready(struct xe_device *xe, bool locked) } /** - * xe_pcode_init: initialize components of PCODE + * xe_pcode_init_early() - Initialize components of PCODE * @tile: tile instance * * This function initializes the xe_pcode component. * To be called once only during probe. + * + * Return: 0 on success or a negative error code on failure. */ -void xe_pcode_init(struct xe_tile *tile) +int xe_pcode_init_early(struct xe_tile *tile) { - drmm_mutex_init(&tile_to_xe(tile)->drm, &tile->pcode.lock); + return drmm_mutex_init(&tile_to_xe(tile)->drm, &tile->pcode.lock); } /** diff --git a/drivers/gpu/drm/xe/xe_pcode.h b/drivers/gpu/drm/xe/xe_pcode.h index 490e4f269607..18260c29e620 100644 --- a/drivers/gpu/drm/xe/xe_pcode.h +++ b/drivers/gpu/drm/xe/xe_pcode.h @@ -12,7 +12,7 @@ struct drm_device; struct xe_device; struct xe_tile; -void xe_pcode_init(struct xe_tile *tile); +int xe_pcode_init_early(struct xe_tile *tile); int xe_pcode_probe_early(struct xe_device *xe); int xe_pcode_ready(struct xe_device *xe, bool locked); int xe_pcode_init_min_freq_table(struct xe_tile *tile, u32 min_gt_freq, diff --git a/drivers/gpu/drm/xe/xe_tile.c b/drivers/gpu/drm/xe/xe_tile.c index c465aae7883c..74d925a337b7 100644 --- a/drivers/gpu/drm/xe/xe_tile.c +++ b/drivers/gpu/drm/xe/xe_tile.c @@ -157,7 +157,9 @@ int xe_tile_init_early(struct xe_tile *tile, struct xe_device *xe, u8 id) if (err) return err; - xe_pcode_init(tile); + err = xe_pcode_init_early(tile); + if (err) + return err; return 0; } -- cgit v1.2.3 From 5ff004fdc7377905f2fe5264b8829d35e14608b8 Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Mon, 1 Jun 2026 13:09:47 -0700 Subject: drm/xe/rtp: Add struct types for RTP tables We currently have a mixture of styles for our RTP tables with respect of how we define the number of entries: * xe_rtp_process_to_sr() expects to receive the number of entries as arguments; * xe_rtp_process() expects the array to have a sentinel at the end of the array; * in xe_rtp_test.c, even though xe_rtp_process_to_sr() does not require a sentinel value, we need to rely on that technique to be able to count xe_rtp_entry_sr entries because simply using ARRAY_SIZE() is not possible. The style used by xe_rtp_process_to_sr() makes it hard to share the tables with other compilation units (e.g. kunit tests), since the number of entries is calculated with ARRAY_SIZE(), which is done at compile time. Since we use the size of the tables to create some bitmasks, using a sentinel style doesn't seem great either. A way to reconcile things into a single style is to have a struct type that would hold the entries array and the number of entries. Since we have xe_rtp_entry and xe_rtp_entry_sr, we would have one type for each. The advantage of the proposed approach is that now we have a nice way to share the tables directly to kunit tests with information about their size. v6: - Removed sentinels that are not needed v5: - Removed added code from conflict resolution issues v4: - Removed conflicts with main branch v3: - No changes v2: - Add compatibility with new xe_rtp_table_sr format for "bad-mcr-reg-forced-to-regular" and "bad-regular-reg-forced-to-mcr" Reviewed-by: Matt Roper Signed-off-by: Gustavo Sousa Signed-off-by: Violet Monti Link: https://patch.msgid.link/20260601200947.2032784-7-violet.monti@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/tests/xe_rtp_test.c | 103 +++++++++++++-------------------- drivers/gpu/drm/xe/xe_hw_engine.c | 14 ++--- drivers/gpu/drm/xe/xe_reg_whitelist.c | 7 +-- drivers/gpu/drm/xe/xe_rtp.c | 31 +++++----- drivers/gpu/drm/xe/xe_rtp.h | 16 ++++- drivers/gpu/drm/xe/xe_rtp_types.h | 10 ++++ drivers/gpu/drm/xe/xe_tuning.c | 45 +++++++------- drivers/gpu/drm/xe/xe_wa.c | 89 ++++++++++++++-------------- 8 files changed, 156 insertions(+), 159 deletions(-) diff --git a/drivers/gpu/drm/xe/tests/xe_rtp_test.c b/drivers/gpu/drm/xe/tests/xe_rtp_test.c index 642f6e090ad0..3d0688d058d9 100644 --- a/drivers/gpu/drm/xe/tests/xe_rtp_test.c +++ b/drivers/gpu/drm/xe/tests/xe_rtp_test.c @@ -54,13 +54,13 @@ struct rtp_to_sr_test_case { unsigned long expected_count_sr_entries; unsigned int expected_sr_errors; unsigned long expected_active; - const struct xe_rtp_entry_sr *entries; + const struct xe_rtp_table_sr table; }; struct rtp_test_case { const char *name; unsigned long expected_active; - const struct xe_rtp_entry *entries; + const struct xe_rtp_table table; }; static bool fake_xe_gt_mcr_check_reg(struct xe_gt *gt, struct xe_reg reg) @@ -289,7 +289,7 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { .expected_active = BIT(0) | BIT(1), .expected_count_sr_entries = 1, /* Different bits on the same register: create a single entry */ - .entries = (const struct xe_rtp_entry_sr[]) { + .table = XE_RTP_TABLE_SR( { XE_RTP_NAME("basic-1"), XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) @@ -298,8 +298,7 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1))) }, - {} - }, + ), }, { .name = "no-match-no-add", @@ -309,7 +308,7 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { .expected_active = BIT(0), .expected_count_sr_entries = 1, /* Don't coalesce second entry since rules don't match */ - .entries = (const struct xe_rtp_entry_sr[]) { + .table = XE_RTP_TABLE_SR( { XE_RTP_NAME("basic-1"), XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) @@ -318,8 +317,7 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { XE_RTP_RULES(FUNC(match_no)), XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1))) }, - {} - }, + ), }, { .name = "two-regs-two-entries", @@ -329,7 +327,7 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { .expected_active = BIT(0) | BIT(1), .expected_count_sr_entries = 2, /* Same bits on different registers are not coalesced */ - .entries = (const struct xe_rtp_entry_sr[]) { + .table = XE_RTP_TABLE_SR( { XE_RTP_NAME("basic-1"), XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) @@ -338,8 +336,7 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(SET(REGULAR_REG2, REG_BIT(0))) }, - {} - }, + ), }, { .name = "clr-one-set-other", @@ -349,7 +346,7 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { .expected_active = BIT(0) | BIT(1), .expected_count_sr_entries = 1, /* Check clr vs set actions on different bits */ - .entries = (const struct xe_rtp_entry_sr[]) { + .table = XE_RTP_TABLE_SR( { XE_RTP_NAME("basic-1"), XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) @@ -358,8 +355,7 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(CLR(REGULAR_REG1, REG_BIT(1))) }, - {} - }, + ), }, { #define TEMP_MASK REG_GENMASK(10, 8) @@ -371,14 +367,13 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { .expected_active = BIT(0), .expected_count_sr_entries = 1, /* Check FIELD_SET works */ - .entries = (const struct xe_rtp_entry_sr[]) { + .table = XE_RTP_TABLE_SR( { XE_RTP_NAME("basic-1"), XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(FIELD_SET(REGULAR_REG1, TEMP_MASK, TEMP_FIELD)) }, - {} - }, + ), #undef TEMP_MASK #undef TEMP_FIELD }, @@ -390,7 +385,7 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { .expected_active = BIT(0) | BIT(1), .expected_count_sr_entries = 1, .expected_sr_errors = 1, - .entries = (const struct xe_rtp_entry_sr[]) { + .table = XE_RTP_TABLE_SR( { XE_RTP_NAME("basic-1"), XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) @@ -400,8 +395,7 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) }, - {} - }, + ), }, { .name = "conflict-not-disjoint", @@ -411,7 +405,7 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { .expected_active = BIT(0) | BIT(1), .expected_count_sr_entries = 1, .expected_sr_errors = 1, - .entries = (const struct xe_rtp_entry_sr[]) { + .table = XE_RTP_TABLE_SR( { XE_RTP_NAME("basic-1"), XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) @@ -421,8 +415,7 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(CLR(REGULAR_REG1, REG_GENMASK(1, 0))) }, - {} - }, + ), }, { .name = "conflict-reg-type", @@ -432,7 +425,7 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { .expected_active = BIT(0) | BIT(1) | BIT(2), .expected_count_sr_entries = 1, .expected_sr_errors = 2, - .entries = (const struct xe_rtp_entry_sr[]) { + .table = XE_RTP_TABLE_SR( { XE_RTP_NAME("basic-1"), XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) @@ -447,8 +440,7 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(SET(MASKED_REG1, REG_BIT(0))) }, - {} - }, + ), }, { .name = "bad-mcr-reg-forced-to-regular", @@ -458,13 +450,12 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { .expected_active = BIT(0), .expected_count_sr_entries = 1, .expected_sr_errors = 1, - .entries = (const struct xe_rtp_entry_sr[]) { + .table = XE_RTP_TABLE_SR( { XE_RTP_NAME("bad-mcr-regular-reg"), XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(SET(BAD_MCR_REG4, REG_BIT(0))) }, - {} - }, + ), }, { .name = "bad-regular-reg-forced-to-mcr", @@ -474,13 +465,12 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { .expected_active = BIT(0), .expected_count_sr_entries = 1, .expected_sr_errors = 1, - .entries = (const struct xe_rtp_entry_sr[]) { + .table = XE_RTP_TABLE_SR( { XE_RTP_NAME("bad-regular-reg"), XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(SET(BAD_REGULAR_REG5, REG_BIT(0))) }, - {} - }, + ), }, }; @@ -492,16 +482,12 @@ static void xe_rtp_process_to_sr_tests(struct kunit *test) struct xe_reg_sr *reg_sr = >->reg_sr; const struct xe_reg_sr_entry *sre, *sr_entry = NULL; struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(gt); - unsigned long idx, count_sr_entries = 0, count_rtp_entries = 0, active = 0; + unsigned long idx, count_sr_entries = 0, active = 0; xe_reg_sr_init(reg_sr, "xe_rtp_to_sr_tests", xe); - while (param->entries[count_rtp_entries].rules) - count_rtp_entries++; - - xe_rtp_process_ctx_enable_active_tracking(&ctx, &active, count_rtp_entries); - xe_rtp_process_to_sr(&ctx, param->entries, count_rtp_entries, - reg_sr, false); + xe_rtp_process_ctx_enable_active_tracking(&ctx, &active, param->table.n_entries); + xe_rtp_process_to_sr(&ctx, ¶m->table, reg_sr, false); xa_for_each(®_sr->xa, idx, sre) { if (idx == param->expected_reg.addr) @@ -534,56 +520,52 @@ static const struct rtp_test_case rtp_cases[] = { { .name = "active1", .expected_active = BIT(0), - .entries = (const struct xe_rtp_entry[]) { + .table = XE_RTP_TABLE( { XE_RTP_NAME("r1"), XE_RTP_RULES(FUNC(match_yes)), }, - {} - }, + ), }, { .name = "active2", .expected_active = BIT(0) | BIT(1), - .entries = (const struct xe_rtp_entry[]) { + .table = XE_RTP_TABLE( { XE_RTP_NAME("r1"), XE_RTP_RULES(FUNC(match_yes)), }, { XE_RTP_NAME("r2"), XE_RTP_RULES(FUNC(match_yes)), }, - {} - }, + ), }, { .name = "active-inactive", .expected_active = BIT(0), - .entries = (const struct xe_rtp_entry[]) { + .table = XE_RTP_TABLE( { XE_RTP_NAME("r1"), XE_RTP_RULES(FUNC(match_yes)), }, { XE_RTP_NAME("r2"), XE_RTP_RULES(FUNC(match_no)), }, - {} - }, + ), }, { .name = "inactive-active", .expected_active = BIT(1), - .entries = (const struct xe_rtp_entry[]) { + .table = XE_RTP_TABLE( { XE_RTP_NAME("r1"), XE_RTP_RULES(FUNC(match_no)), }, { XE_RTP_NAME("r2"), XE_RTP_RULES(FUNC(match_yes)), }, - {} - }, + ), }, { .name = "inactive-active-inactive", .expected_active = BIT(1), - .entries = (const struct xe_rtp_entry[]) { + .table = XE_RTP_TABLE( { XE_RTP_NAME("r1"), XE_RTP_RULES(FUNC(match_no)), }, @@ -593,13 +575,12 @@ static const struct rtp_test_case rtp_cases[] = { { XE_RTP_NAME("r3"), XE_RTP_RULES(FUNC(match_no)), }, - {} - }, + ), }, { .name = "inactive-inactive-inactive", .expected_active = 0, - .entries = (const struct xe_rtp_entry[]) { + .table = XE_RTP_TABLE( { XE_RTP_NAME("r1"), XE_RTP_RULES(FUNC(match_no)), }, @@ -609,8 +590,7 @@ static const struct rtp_test_case rtp_cases[] = { { XE_RTP_NAME("r3"), XE_RTP_RULES(FUNC(match_no)), }, - {} - }, + ), }, }; @@ -620,13 +600,10 @@ static void xe_rtp_process_tests(struct kunit *test) struct xe_device *xe = test->priv; struct xe_gt *gt = xe_device_get_root_tile(xe)->primary_gt; struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(gt); - unsigned long count_rtp_entries = 0, active = 0; - - while (param->entries[count_rtp_entries].rules) - count_rtp_entries++; + unsigned long active = 0; - xe_rtp_process_ctx_enable_active_tracking(&ctx, &active, count_rtp_entries); - xe_rtp_process(&ctx, param->entries); + xe_rtp_process_ctx_enable_active_tracking(&ctx, &active, param->table.n_entries); + xe_rtp_process(&ctx, ¶m->table); KUNIT_EXPECT_EQ(test, active, param->expected_active); } diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c index 8c66ff6f3d3c..98265293f2dc 100644 --- a/drivers/gpu/drm/xe/xe_hw_engine.c +++ b/drivers/gpu/drm/xe/xe_hw_engine.c @@ -346,7 +346,7 @@ hw_engine_setup_default_lrc_state(struct xe_hw_engine *hwe) u32 blit_cctl_val = REG_FIELD_PREP(BLIT_CCTL_DST_MOCS_MASK, mocs_write_idx) | REG_FIELD_PREP(BLIT_CCTL_SRC_MOCS_MASK, mocs_read_idx); struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe); - const struct xe_rtp_entry_sr lrc_setup[] = { + const struct xe_rtp_table_sr lrc_setup = XE_RTP_TABLE_SR( /* * Some blitter commands do not have a field for MOCS, those * commands will use MOCS index pointed by BLIT_CCTL. @@ -369,10 +369,9 @@ hw_engine_setup_default_lrc_state(struct xe_hw_engine *hwe) PREEMPT_GPGPU_THREAD_GROUP_LEVEL)), XE_RTP_ENTRY_FLAG(FOREACH_ENGINE) }, - }; + ); - xe_rtp_process_to_sr(&ctx, lrc_setup, ARRAY_SIZE(lrc_setup), - &hwe->reg_lrc, true); + xe_rtp_process_to_sr(&ctx, &lrc_setup, &hwe->reg_lrc, true); } void xe_hw_engine_setup_reg_lrc(struct xe_hw_engine *hwe) @@ -408,7 +407,7 @@ hw_engine_setup_default_state(struct xe_hw_engine *hwe) u32 ring_cmd_cctl_val = REG_FIELD_PREP(CMD_CCTL_WRITE_OVERRIDE_MASK, mocs_write_idx) | REG_FIELD_PREP(CMD_CCTL_READ_OVERRIDE_MASK, mocs_read_idx); struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe); - const struct xe_rtp_entry_sr engine_entries[] = { + const struct xe_rtp_table_sr engine_sr = XE_RTP_TABLE_SR( { XE_RTP_NAME("RING_CMD_CCTL_default_MOCS"), XE_RTP_RULES(FUNC(xe_rtp_match_always)), XE_RTP_ACTIONS(FIELD_SET(RING_CMD_CCTL(0), @@ -465,10 +464,9 @@ hw_engine_setup_default_state(struct xe_hw_engine *hwe) XE_RTP_ACTIONS(SET(GFX_MODE(0), GFX_MSIX_INTERRUPT_ENABLE, XE_RTP_ACTION_FLAG(ENGINE_BASE))) }, - }; + ); - xe_rtp_process_to_sr(&ctx, engine_entries, ARRAY_SIZE(engine_entries), - &hwe->reg_sr, false); + xe_rtp_process_to_sr(&ctx, &engine_sr, &hwe->reg_sr, false); } static const struct engine_info *find_engine_info(enum xe_engine_class class, int instance) diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.c b/drivers/gpu/drm/xe/xe_reg_whitelist.c index fb65940848d7..2e84b1c49f37 100644 --- a/drivers/gpu/drm/xe/xe_reg_whitelist.c +++ b/drivers/gpu/drm/xe/xe_reg_whitelist.c @@ -41,7 +41,7 @@ static bool match_multi_queue_class(const struct xe_device *xe, return xe_gt_supports_multi_queue(gt, hwe->class); } -static const struct xe_rtp_entry_sr register_whitelist[] = { +static const struct xe_rtp_table_sr register_whitelist = XE_RTP_TABLE_SR( { XE_RTP_NAME("WaAllowPMDepthAndInvocationCountAccessFromUMD, 1408556865"), XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 1210), ENGINE_CLASS(RENDER)), XE_RTP_ACTIONS(WHITELIST(PS_INVOCATION_COUNT, @@ -154,7 +154,7 @@ static const struct xe_rtp_entry_sr register_whitelist[] = { XE_RTP_RULES(FUNC(match_has_mert), ENGINE_CLASS(COPY)), XE_RTP_ACTIONS(WHITELIST_OA_MERT_MMIO_TRG) }, -}; +); static void whitelist_apply_to_hwe(struct xe_hw_engine *hwe) { @@ -202,8 +202,7 @@ void xe_reg_whitelist_process_engine(struct xe_hw_engine *hwe) { struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe); - xe_rtp_process_to_sr(&ctx, register_whitelist, ARRAY_SIZE(register_whitelist), - &hwe->reg_whitelist, false); + xe_rtp_process_to_sr(&ctx, ®ister_whitelist, &hwe->reg_whitelist, false); whitelist_apply_to_hwe(hwe); } diff --git a/drivers/gpu/drm/xe/xe_rtp.c b/drivers/gpu/drm/xe/xe_rtp.c index dec9d94e6fb0..83a40e1f9528 100644 --- a/drivers/gpu/drm/xe/xe_rtp.c +++ b/drivers/gpu/drm/xe/xe_rtp.c @@ -326,8 +326,7 @@ static void rtp_mark_active(struct xe_device *xe, * xe_rtp_process_to_sr - Process all rtp @entries, adding the matching ones to * the save-restore argument. * @ctx: The context for processing the table, with one of device, gt or hwe - * @entries: Table with RTP definitions - * @n_entries: Number of entries to process, usually ARRAY_SIZE(entries) + * @table: Table with RTP definitions * @sr: Save-restore struct where matching rules execute the action. This can be * viewed as the "coalesced view" of multiple the tables. The bits for each * register set are expected not to collide with previously added entries @@ -339,12 +338,10 @@ static void rtp_mark_active(struct xe_device *xe, * used to calculate the right register offset */ void xe_rtp_process_to_sr(struct xe_rtp_process_ctx *ctx, - const struct xe_rtp_entry_sr *entries, - size_t n_entries, + const struct xe_rtp_table_sr *table, struct xe_reg_sr *sr, bool process_in_vf) { - const struct xe_rtp_entry_sr *entry; struct xe_hw_engine *hwe = NULL; struct xe_gt *gt = NULL; struct xe_device *xe = NULL; @@ -354,9 +351,10 @@ void xe_rtp_process_to_sr(struct xe_rtp_process_ctx *ctx, if (!process_in_vf && IS_SRIOV_VF(xe)) return; - xe_assert(xe, entries); + xe_assert(xe, table->entries); - for (entry = entries; entry - entries < n_entries; entry++) { + for (size_t i = 0; i < table->n_entries; i++) { + const struct xe_rtp_entry_sr *entry = &table->entries[i]; bool match = false; if (entry->flags & XE_RTP_ENTRY_FLAG_FOREACH_ENGINE) { @@ -371,37 +369,40 @@ void xe_rtp_process_to_sr(struct xe_rtp_process_ctx *ctx, } if (match) - rtp_mark_active(xe, ctx, entry - entries); + rtp_mark_active(xe, ctx, i); } } EXPORT_SYMBOL_IF_KUNIT(xe_rtp_process_to_sr); /** - * xe_rtp_process - Process all rtp @entries, without running any action + * xe_rtp_process - Process all entries in rtp @table, without running any action * @ctx: The context for processing the table, with one of device, gt or hwe - * @entries: Table with RTP definitions + * @table: Table with RTP definitions * - * Walk the table pointed by @entries (with an empty sentinel), executing the + * Walk the table pointed by @table, executing the * rules. One difference from xe_rtp_process_to_sr(): there is no action * associated with each entry since this uses struct xe_rtp_entry. Its main use * is for marking active workarounds via * xe_rtp_process_ctx_enable_active_tracking(). */ void xe_rtp_process(struct xe_rtp_process_ctx *ctx, - const struct xe_rtp_entry *entries) + const struct xe_rtp_table *table) { - const struct xe_rtp_entry *entry; struct xe_hw_engine *hwe; struct xe_gt *gt; struct xe_device *xe; rtp_get_context(ctx, &hwe, >, &xe); - for (entry = entries; entry && entry->rules; entry++) { + xe_assert(xe, table->entries); + + for (size_t i = 0; i < table->n_entries; i++) { + const struct xe_rtp_entry *entry = &table->entries[i]; + if (!rule_matches(xe, gt, hwe, entry->rules, entry->n_rules)) continue; - rtp_mark_active(xe, ctx, entry - entries); + rtp_mark_active(xe, ctx, i); } } EXPORT_SYMBOL_IF_KUNIT(xe_rtp_process); diff --git a/drivers/gpu/drm/xe/xe_rtp.h b/drivers/gpu/drm/xe/xe_rtp.h index e4f1930ca1c3..4e3cfd69f922 100644 --- a/drivers/gpu/drm/xe/xe_rtp.h +++ b/drivers/gpu/drm/xe/xe_rtp.h @@ -461,6 +461,16 @@ struct xe_reg_sr; XE_RTP_PASTE_FOREACH(ACTION_, COMMA, (__VA_ARGS__)) \ } +#define XE_RTP_TABLE_SR(...) { \ + .entries = (const struct xe_rtp_entry_sr[]){__VA_ARGS__}, \ + .n_entries = ARRAY_SIZE(((const struct xe_rtp_entry_sr[]){__VA_ARGS__})), \ +} + +#define XE_RTP_TABLE(...) { \ + .entries = (const struct xe_rtp_entry[]){__VA_ARGS__}, \ + .n_entries = ARRAY_SIZE(((const struct xe_rtp_entry[]){__VA_ARGS__})), \ +} + #define XE_RTP_PROCESS_CTX_INITIALIZER(arg__) _Generic((arg__), \ struct xe_hw_engine * : (struct xe_rtp_process_ctx){ { (void *)(arg__) }, XE_RTP_PROCESS_TYPE_ENGINE }, \ struct xe_gt * : (struct xe_rtp_process_ctx){ { (void *)(arg__) }, XE_RTP_PROCESS_TYPE_GT }, \ @@ -471,12 +481,12 @@ void xe_rtp_process_ctx_enable_active_tracking(struct xe_rtp_process_ctx *ctx, size_t n_entries); void xe_rtp_process_to_sr(struct xe_rtp_process_ctx *ctx, - const struct xe_rtp_entry_sr *entries, - size_t n_entries, struct xe_reg_sr *sr, + const struct xe_rtp_table_sr *table, + struct xe_reg_sr *sr, bool process_in_vf); void xe_rtp_process(struct xe_rtp_process_ctx *ctx, - const struct xe_rtp_entry *entries); + const struct xe_rtp_table *table); /* Match functions to be used with XE_RTP_MATCH_FUNC */ diff --git a/drivers/gpu/drm/xe/xe_rtp_types.h b/drivers/gpu/drm/xe/xe_rtp_types.h index 0265c16d2762..58018ae4f8cc 100644 --- a/drivers/gpu/drm/xe/xe_rtp_types.h +++ b/drivers/gpu/drm/xe/xe_rtp_types.h @@ -112,6 +112,16 @@ struct xe_rtp_entry { u8 n_rules; }; +struct xe_rtp_table_sr { + const struct xe_rtp_entry_sr *entries; + size_t n_entries; +}; + +struct xe_rtp_table { + const struct xe_rtp_entry *entries; + size_t n_entries; +}; + enum xe_rtp_process_type { XE_RTP_PROCESS_TYPE_DEVICE, XE_RTP_PROCESS_TYPE_GT, diff --git a/drivers/gpu/drm/xe/xe_tuning.c b/drivers/gpu/drm/xe/xe_tuning.c index 9a1b3862e192..bf3fad9cdbef 100644 --- a/drivers/gpu/drm/xe/xe_tuning.c +++ b/drivers/gpu/drm/xe/xe_tuning.c @@ -20,7 +20,7 @@ #undef XE_REG_MCR #define XE_REG_MCR(...) XE_REG(__VA_ARGS__, .mcr = 1) -static const struct xe_rtp_entry_sr gt_tunings[] = { +static const struct xe_rtp_table_sr gt_tunings = XE_RTP_TABLE_SR( { XE_RTP_NAME("Tuning: Blend Fill Caching Optimization Disable"), XE_RTP_RULES(PLATFORM(DG2)), XE_RTP_ACTIONS(SET(XEHP_L3SCQREG7, BLEND_FILL_CACHING_OPT_DIS)) @@ -100,9 +100,9 @@ static const struct xe_rtp_entry_sr gt_tunings[] = { XE_RTP_ACTIONS(FIELD_SET(GAMSTLB_CTRL, BANK_HASH_MODE, BANK_HASH_4KB_MODE)) }, -}; +); -static const struct xe_rtp_entry_sr engine_tunings[] = { +static const struct xe_rtp_table_sr engine_tunings = XE_RTP_TABLE_SR( { XE_RTP_NAME("Tuning: L3 Hashing Mask"), XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 1210), FUNC(xe_rtp_match_first_render_or_compute)), @@ -129,9 +129,9 @@ static const struct xe_rtp_entry_sr engine_tunings[] = { FUNC(xe_rtp_match_first_render_or_compute)), XE_RTP_ACTIONS(SET(TDL_TSL_CHICKEN2, TILEY_LOCALID)) }, -}; +); -static const struct xe_rtp_entry_sr lrc_tunings[] = { +static const struct xe_rtp_table_sr lrc_tunings = XE_RTP_TABLE_SR( { XE_RTP_NAME("Tuning: Windower HW Filtering"), XE_RTP_RULES(GRAPHICS_VERSION_RANGE(3000, 3599), ENGINE_CLASS(RENDER)), XE_RTP_ACTIONS(SET(XEHP_COMMON_SLICE_CHICKEN4, HW_FILTERING)) @@ -171,7 +171,7 @@ static const struct xe_rtp_entry_sr lrc_tunings[] = { XE_RTP_ACTIONS(FIELD_SET(FF_MODE, VS_HIT_MAX_VALUE_MASK, REG_FIELD_PREP(VS_HIT_MAX_VALUE_MASK, 0x3f))) }, -}; +); /** * xe_tuning_init - initialize gt with tunings bookkeeping @@ -185,9 +185,9 @@ int xe_tuning_init(struct xe_gt *gt) size_t n_lrc, n_engine, n_gt, total; unsigned long *p; - n_gt = BITS_TO_LONGS(ARRAY_SIZE(gt_tunings)); - n_engine = BITS_TO_LONGS(ARRAY_SIZE(engine_tunings)); - n_lrc = BITS_TO_LONGS(ARRAY_SIZE(lrc_tunings)); + n_gt = BITS_TO_LONGS(gt_tunings.n_entries); + n_engine = BITS_TO_LONGS(engine_tunings.n_entries); + n_lrc = BITS_TO_LONGS(lrc_tunings.n_entries); total = n_gt + n_engine + n_lrc; p = drmm_kzalloc(&xe->drm, sizeof(*p) * total, GFP_KERNEL); @@ -210,9 +210,8 @@ void xe_tuning_process_gt(struct xe_gt *gt) xe_rtp_process_ctx_enable_active_tracking(&ctx, gt->tuning_active.gt, - ARRAY_SIZE(gt_tunings)); - xe_rtp_process_to_sr(&ctx, gt_tunings, ARRAY_SIZE(gt_tunings), - >->reg_sr, false); + gt_tunings.n_entries); + xe_rtp_process_to_sr(&ctx, >_tunings, >->reg_sr, false); } EXPORT_SYMBOL_IF_KUNIT(xe_tuning_process_gt); @@ -222,9 +221,8 @@ void xe_tuning_process_engine(struct xe_hw_engine *hwe) xe_rtp_process_ctx_enable_active_tracking(&ctx, hwe->gt->tuning_active.engine, - ARRAY_SIZE(engine_tunings)); - xe_rtp_process_to_sr(&ctx, engine_tunings, ARRAY_SIZE(engine_tunings), - &hwe->reg_sr, false); + engine_tunings.n_entries); + xe_rtp_process_to_sr(&ctx, &engine_tunings, &hwe->reg_sr, false); } EXPORT_SYMBOL_IF_KUNIT(xe_tuning_process_engine); @@ -242,9 +240,8 @@ void xe_tuning_process_lrc(struct xe_hw_engine *hwe) xe_rtp_process_ctx_enable_active_tracking(&ctx, hwe->gt->tuning_active.lrc, - ARRAY_SIZE(lrc_tunings)); - xe_rtp_process_to_sr(&ctx, lrc_tunings, ARRAY_SIZE(lrc_tunings), - &hwe->reg_lrc, true); + lrc_tunings.n_entries); + xe_rtp_process_to_sr(&ctx, &lrc_tunings, &hwe->reg_lrc, true); } /** @@ -259,18 +256,18 @@ int xe_tuning_dump(struct xe_gt *gt, struct drm_printer *p) size_t idx; drm_printf(p, "GT Tunings\n"); - for_each_set_bit(idx, gt->tuning_active.gt, ARRAY_SIZE(gt_tunings)) - drm_printf_indent(p, 1, "%s\n", gt_tunings[idx].name); + for_each_set_bit(idx, gt->tuning_active.gt, gt_tunings.n_entries) + drm_printf_indent(p, 1, "%s\n", gt_tunings.entries[idx].name); drm_puts(p, "\n"); drm_printf(p, "Engine Tunings\n"); - for_each_set_bit(idx, gt->tuning_active.engine, ARRAY_SIZE(engine_tunings)) - drm_printf_indent(p, 1, "%s\n", engine_tunings[idx].name); + for_each_set_bit(idx, gt->tuning_active.engine, engine_tunings.n_entries) + drm_printf_indent(p, 1, "%s\n", engine_tunings.entries[idx].name); drm_puts(p, "\n"); drm_printf(p, "LRC Tunings\n"); - for_each_set_bit(idx, gt->tuning_active.lrc, ARRAY_SIZE(lrc_tunings)) - drm_printf_indent(p, 1, "%s\n", lrc_tunings[idx].name); + for_each_set_bit(idx, gt->tuning_active.lrc, lrc_tunings.n_entries) + drm_printf_indent(p, 1, "%s\n", lrc_tunings.entries[idx].name); return 0; } diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c index cb811f8a7781..b9d9fe0801aa 100644 --- a/drivers/gpu/drm/xe/xe_wa.c +++ b/drivers/gpu/drm/xe/xe_wa.c @@ -130,7 +130,7 @@ __diag_push(); __diag_ignore_all("-Woverride-init", "Allow field overrides in table"); -static const struct xe_rtp_entry_sr gt_was[] = { +static const struct xe_rtp_table_sr gt_was = XE_RTP_TABLE_SR( /* Workarounds applying over a range of IPs */ { XE_RTP_NAME("14011060649"), @@ -306,9 +306,9 @@ static const struct xe_rtp_entry_sr gt_was[] = { XE_RTP_RULES(GRAPHICS_VERSION(3510), GRAPHICS_STEP(A0, B0)), XE_RTP_ACTIONS(SET(GUC_INTR_CHICKEN, DISABLE_SIGNALING_ENGINES)) }, -}; +); -static const struct xe_rtp_entry_sr engine_was[] = { +static const struct xe_rtp_table_sr engine_was = XE_RTP_TABLE_SR( /* Workarounds applying over a range of IPs */ { XE_RTP_NAME("22010931296, 18011464164, 14010919138"), @@ -614,9 +614,9 @@ static const struct xe_rtp_entry_sr engine_was[] = { FUNC(xe_rtp_match_first_render_or_compute)), XE_RTP_ACTIONS(SET(TDL_CHICKEN, BIT_APQ_OPT_DIS)) }, -}; +); -static const struct xe_rtp_entry_sr lrc_was[] = { +static const struct xe_rtp_table_sr lrc_was = XE_RTP_TABLE_SR( { XE_RTP_NAME("16011163337"), XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 1210), ENGINE_CLASS(RENDER)), /* read verification is ignored due to 1608008084. */ @@ -794,21 +794,29 @@ static const struct xe_rtp_entry_sr lrc_was[] = { ENGINE_CLASS(RENDER)), XE_RTP_ACTIONS(SET(CHICKEN_RASTER_1, DIS_CLIP_NEGATIVE_BOUNDING_BOX)) }, -}; +); -static __maybe_unused const struct xe_rtp_entry oob_was[] = { +static const struct xe_rtp_entry oob_was_entries[] = { #include - {} }; -static_assert(ARRAY_SIZE(oob_was) - 1 == _XE_WA_OOB_COUNT); +static_assert(ARRAY_SIZE(oob_was_entries) == _XE_WA_OOB_COUNT); -static __maybe_unused const struct xe_rtp_entry device_oob_was[] = { +static __maybe_unused const struct xe_rtp_table oob_was = { + .entries = oob_was_entries, + .n_entries = ARRAY_SIZE(oob_was_entries), +}; + +static const struct xe_rtp_entry device_oob_was_entries[] = { #include - {} }; -static_assert(ARRAY_SIZE(device_oob_was) - 1 == _XE_DEVICE_WA_OOB_COUNT); +static_assert(ARRAY_SIZE(device_oob_was_entries) == _XE_DEVICE_WA_OOB_COUNT); + +static __maybe_unused const struct xe_rtp_table device_oob_was = { + .entries = device_oob_was_entries, + .n_entries = ARRAY_SIZE(device_oob_was_entries), +}; __diag_pop(); @@ -824,10 +832,10 @@ void xe_wa_process_device_oob(struct xe_device *xe) { struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(xe); - xe_rtp_process_ctx_enable_active_tracking(&ctx, xe->wa_active.oob, ARRAY_SIZE(device_oob_was)); + xe_rtp_process_ctx_enable_active_tracking(&ctx, xe->wa_active.oob, device_oob_was.n_entries); xe->wa_active.oob_initialized = true; - xe_rtp_process(&ctx, device_oob_was); + xe_rtp_process(&ctx, &device_oob_was); } /** @@ -842,9 +850,9 @@ void xe_wa_process_gt_oob(struct xe_gt *gt) struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(gt); xe_rtp_process_ctx_enable_active_tracking(&ctx, gt->wa_active.oob, - ARRAY_SIZE(oob_was)); + oob_was.n_entries); gt->wa_active.oob_initialized = true; - xe_rtp_process(&ctx, oob_was); + xe_rtp_process(&ctx, &oob_was); } /** @@ -859,9 +867,8 @@ void xe_wa_process_gt(struct xe_gt *gt) struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(gt); xe_rtp_process_ctx_enable_active_tracking(&ctx, gt->wa_active.gt, - ARRAY_SIZE(gt_was)); - xe_rtp_process_to_sr(&ctx, gt_was, ARRAY_SIZE(gt_was), - >->reg_sr, false); + gt_was.n_entries); + xe_rtp_process_to_sr(&ctx, >_was, >->reg_sr, false); } EXPORT_SYMBOL_IF_KUNIT(xe_wa_process_gt); @@ -878,9 +885,8 @@ void xe_wa_process_engine(struct xe_hw_engine *hwe) struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe); xe_rtp_process_ctx_enable_active_tracking(&ctx, hwe->gt->wa_active.engine, - ARRAY_SIZE(engine_was)); - xe_rtp_process_to_sr(&ctx, engine_was, ARRAY_SIZE(engine_was), - &hwe->reg_sr, false); + engine_was.n_entries); + xe_rtp_process_to_sr(&ctx, &engine_was, &hwe->reg_sr, false); } /** @@ -896,9 +902,8 @@ void xe_wa_process_lrc(struct xe_hw_engine *hwe) struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe); xe_rtp_process_ctx_enable_active_tracking(&ctx, hwe->gt->wa_active.lrc, - ARRAY_SIZE(lrc_was)); - xe_rtp_process_to_sr(&ctx, lrc_was, ARRAY_SIZE(lrc_was), - &hwe->reg_lrc, true); + lrc_was.n_entries); + xe_rtp_process_to_sr(&ctx, &lrc_was, &hwe->reg_lrc, true); } /** @@ -912,7 +917,7 @@ int xe_wa_device_init(struct xe_device *xe) unsigned long *p; p = drmm_kzalloc(&xe->drm, - sizeof(*p) * BITS_TO_LONGS(ARRAY_SIZE(device_oob_was)), + sizeof(*p) * BITS_TO_LONGS(device_oob_was.n_entries), GFP_KERNEL); if (!p) @@ -935,10 +940,10 @@ int xe_wa_gt_init(struct xe_gt *gt) size_t n_oob, n_lrc, n_engine, n_gt, total; unsigned long *p; - n_gt = BITS_TO_LONGS(ARRAY_SIZE(gt_was)); - n_engine = BITS_TO_LONGS(ARRAY_SIZE(engine_was)); - n_lrc = BITS_TO_LONGS(ARRAY_SIZE(lrc_was)); - n_oob = BITS_TO_LONGS(ARRAY_SIZE(oob_was)); + n_gt = BITS_TO_LONGS(gt_was.n_entries); + n_engine = BITS_TO_LONGS(engine_was.n_entries); + n_lrc = BITS_TO_LONGS(lrc_was.n_entries); + n_oob = BITS_TO_LONGS(oob_was.n_entries); total = n_gt + n_engine + n_lrc + n_oob; p = drmm_kzalloc(&xe->drm, sizeof(*p) * total, GFP_KERNEL); @@ -962,9 +967,9 @@ void xe_wa_device_dump(struct xe_device *xe, struct drm_printer *p) size_t idx; drm_printf(p, "Device OOB Workarounds\n"); - for_each_set_bit(idx, xe->wa_active.oob, ARRAY_SIZE(device_oob_was)) - if (device_oob_was[idx].name) - drm_printf_indent(p, 1, "%s\n", device_oob_was[idx].name); + for_each_set_bit(idx, xe->wa_active.oob, device_oob_was.n_entries) + if (device_oob_was.entries[idx].name) + drm_printf_indent(p, 1, "%s\n", device_oob_was.entries[idx].name); } /** @@ -979,24 +984,24 @@ int xe_wa_gt_dump(struct xe_gt *gt, struct drm_printer *p) size_t idx; drm_printf(p, "GT Workarounds\n"); - for_each_set_bit(idx, gt->wa_active.gt, ARRAY_SIZE(gt_was)) - drm_printf_indent(p, 1, "%s\n", gt_was[idx].name); + for_each_set_bit(idx, gt->wa_active.gt, gt_was.n_entries) + drm_printf_indent(p, 1, "%s\n", gt_was.entries[idx].name); drm_puts(p, "\n"); drm_printf(p, "Engine Workarounds\n"); - for_each_set_bit(idx, gt->wa_active.engine, ARRAY_SIZE(engine_was)) - drm_printf_indent(p, 1, "%s\n", engine_was[idx].name); + for_each_set_bit(idx, gt->wa_active.engine, engine_was.n_entries) + drm_printf_indent(p, 1, "%s\n", engine_was.entries[idx].name); drm_puts(p, "\n"); drm_printf(p, "LRC Workarounds\n"); - for_each_set_bit(idx, gt->wa_active.lrc, ARRAY_SIZE(lrc_was)) - drm_printf_indent(p, 1, "%s\n", lrc_was[idx].name); + for_each_set_bit(idx, gt->wa_active.lrc, lrc_was.n_entries) + drm_printf_indent(p, 1, "%s\n", lrc_was.entries[idx].name); drm_puts(p, "\n"); drm_printf(p, "OOB Workarounds\n"); - for_each_set_bit(idx, gt->wa_active.oob, ARRAY_SIZE(oob_was)) - if (oob_was[idx].name) - drm_printf_indent(p, 1, "%s\n", oob_was[idx].name); + for_each_set_bit(idx, gt->wa_active.oob, oob_was.n_entries) + if (oob_was.entries[idx].name) + drm_printf_indent(p, 1, "%s\n", oob_was.entries[idx].name); return 0; } -- cgit v1.2.3 From e9845449e37f5a5eb1508760ef048211d7e261ff Mon Sep 17 00:00:00 2001 From: Violet Monti Date: Mon, 1 Jun 2026 13:09:48 -0700 Subject: drm/xe/rtp: Ensure gt_was doesn't evaluate rules with engine types It is currently possible for a RTP rule, and subsequently a workaround, to expect contexts that may not be present when the workaround is applied. For example, the workarounds in the engine_was[] in drm/xe/xe_wa.c expect an engine entity to be active. Conversely, the gt_was[] is not depending on an engine entity to implement its workarounds. This kunit test addition checks the gt_was[] workaround list for any workarounds with XEP_RTP_ENGINE_CLASS() rules. If a workaround does have one of these rules, the workaround is then checked for the "FOREACH_ENGINE" flag, which ensures the workaround is implemented properly. The result of this test is an expectation failure if a workaround has an improper XE_RTP_ENGINE_CLASS() rule setup, and aims to prevent future issues of gt_was workarounds being applied without proper contexts. The gt_tunings[] RTP table has the same functional layout and requirements as gt_was[], so it shares the same kunit test function, minimizing excessive code. v6: - No change v5: - Remove unnecessary headers from xe_rtp_table_test.c v4: - No change v3: - Removed "VISIBLE_IF_KUNIT" keyword from xe_wa.h - Added gt_tunings[] for testing - Reworked KUNIT_EXPECT_TRUE() for easier parsing of errors v2: - Moved contents of xe_rtp_tables_test.h to .c and removed file - Renamed macro RTP_KUNIT_ARRAY_PARAM to RTP_TABLE_PARAM - Removed unnecessary functions and iterative components from generated _gen_params functions and implemented usage of table name and WA number as entry name - Condensed xe_rtp_table_gt_test() to use KUNIT_EXPECT_TRUE with no message statement - Removed xe_rtp_table_test_init() and xe_rtp_table_test_exit() as fake device initialization is not necessary Reviewed-by: Gustavo Sousa Signed-off-by: Violet Monti Link: https://patch.msgid.link/20260601200947.2032784-8-violet.monti@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/tests/Makefile | 1 + drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c | 53 +++++++++++++++++++++++++++ drivers/gpu/drm/xe/xe_tuning.c | 3 +- drivers/gpu/drm/xe/xe_tuning.h | 6 +++ drivers/gpu/drm/xe/xe_wa.c | 3 +- drivers/gpu/drm/xe/xe_wa.h | 5 +++ 6 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c diff --git a/drivers/gpu/drm/xe/tests/Makefile b/drivers/gpu/drm/xe/tests/Makefile index 0e3408f4952c..f7aa47f11a36 100644 --- a/drivers/gpu/drm/xe/tests/Makefile +++ b/drivers/gpu/drm/xe/tests/Makefile @@ -9,5 +9,6 @@ obj-$(CONFIG_DRM_XE_KUNIT_TEST) += xe_test.o xe_test-y = xe_test_mod.o \ xe_args_test.o \ xe_pci_test.o \ + xe_rtp_tables_test.o \ xe_rtp_test.o \ xe_wa_test.o diff --git a/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c b/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c new file mode 100644 index 000000000000..7dd77133bc42 --- /dev/null +++ b/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright © 2026 Intel Corporation + */ + +#include + +#include "xe_rtp_types.h" +#include "xe_tuning.h" +#include "xe_wa.h" + +#define RTP_TABLE_PARAM(table) \ + static const void *table##_gen_params(struct kunit *test, \ + const void *prev, char *desc) \ + { \ + typeof((table.entries)[0]) *__next = prev ? \ + ((typeof(__next))prev) + 1 : (table.entries); \ + if (__next - table.entries < table.n_entries) { \ + scnprintf(desc, KUNIT_PARAM_DESC_SIZE, #table "/%s", __next->name); \ + return __next; \ + } \ + return NULL; \ + } + +static void xe_rtp_table_gt_test(struct kunit *test) +{ + const struct xe_rtp_entry_sr *entry = test->param_value; + + for (int i = 0; i < entry->n_rules; i++) { + KUNIT_EXPECT_TRUE(test, + entry->rules[i].match_type != XE_RTP_MATCH_ENGINE_CLASS || + entry->flags & XE_RTP_ENTRY_FLAG_FOREACH_ENGINE); + KUNIT_EXPECT_TRUE(test, + entry->rules[i].match_type != XE_RTP_MATCH_NOT_ENGINE_CLASS || + entry->flags & XE_RTP_ENTRY_FLAG_FOREACH_ENGINE); + } +} + +RTP_TABLE_PARAM(gt_was); +RTP_TABLE_PARAM(gt_tunings); + +static struct kunit_case xe_rtp_table_tests[] = { + KUNIT_CASE_PARAM(xe_rtp_table_gt_test, gt_was_gen_params), + KUNIT_CASE_PARAM(xe_rtp_table_gt_test, gt_tunings_gen_params), + {} +}; + +static struct kunit_suite xe_rtp_tables_test_suite = { + .name = "xe_rtp_tables_test", + .test_cases = xe_rtp_table_tests, +}; + +kunit_test_suite(xe_rtp_tables_test_suite); diff --git a/drivers/gpu/drm/xe/xe_tuning.c b/drivers/gpu/drm/xe/xe_tuning.c index bf3fad9cdbef..bcec40ca2d35 100644 --- a/drivers/gpu/drm/xe/xe_tuning.c +++ b/drivers/gpu/drm/xe/xe_tuning.c @@ -20,7 +20,7 @@ #undef XE_REG_MCR #define XE_REG_MCR(...) XE_REG(__VA_ARGS__, .mcr = 1) -static const struct xe_rtp_table_sr gt_tunings = XE_RTP_TABLE_SR( +VISIBLE_IF_KUNIT const struct xe_rtp_table_sr gt_tunings = XE_RTP_TABLE_SR( { XE_RTP_NAME("Tuning: Blend Fill Caching Optimization Disable"), XE_RTP_RULES(PLATFORM(DG2)), XE_RTP_ACTIONS(SET(XEHP_L3SCQREG7, BLEND_FILL_CACHING_OPT_DIS)) @@ -101,6 +101,7 @@ static const struct xe_rtp_table_sr gt_tunings = XE_RTP_TABLE_SR( BANK_HASH_4KB_MODE)) }, ); +EXPORT_SYMBOL_IF_KUNIT(gt_tunings); static const struct xe_rtp_table_sr engine_tunings = XE_RTP_TABLE_SR( { XE_RTP_NAME("Tuning: L3 Hashing Mask"), diff --git a/drivers/gpu/drm/xe/xe_tuning.h b/drivers/gpu/drm/xe/xe_tuning.h index d18e187debf6..869564e3e992 100644 --- a/drivers/gpu/drm/xe/xe_tuning.h +++ b/drivers/gpu/drm/xe/xe_tuning.h @@ -6,6 +6,8 @@ #ifndef _XE_TUNING_H_ #define _XE_TUNING_H_ +#include + struct drm_printer; struct xe_gt; struct xe_hw_engine; @@ -16,4 +18,8 @@ void xe_tuning_process_engine(struct xe_hw_engine *hwe); void xe_tuning_process_lrc(struct xe_hw_engine *hwe); int xe_tuning_dump(struct xe_gt *gt, struct drm_printer *p); +#if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST) +extern const struct xe_rtp_table_sr gt_tunings; +#endif + #endif diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c index b9d9fe0801aa..1a1e04215f21 100644 --- a/drivers/gpu/drm/xe/xe_wa.c +++ b/drivers/gpu/drm/xe/xe_wa.c @@ -130,7 +130,7 @@ __diag_push(); __diag_ignore_all("-Woverride-init", "Allow field overrides in table"); -static const struct xe_rtp_table_sr gt_was = XE_RTP_TABLE_SR( +VISIBLE_IF_KUNIT const struct xe_rtp_table_sr gt_was = XE_RTP_TABLE_SR( /* Workarounds applying over a range of IPs */ { XE_RTP_NAME("14011060649"), @@ -307,6 +307,7 @@ static const struct xe_rtp_table_sr gt_was = XE_RTP_TABLE_SR( XE_RTP_ACTIONS(SET(GUC_INTR_CHICKEN, DISABLE_SIGNALING_ENGINES)) }, ); +EXPORT_SYMBOL_IF_KUNIT(gt_was); static const struct xe_rtp_table_sr engine_was = XE_RTP_TABLE_SR( /* Workarounds applying over a range of IPs */ diff --git a/drivers/gpu/drm/xe/xe_wa.h b/drivers/gpu/drm/xe/xe_wa.h index a5f7d33c1b32..8784b491dde7 100644 --- a/drivers/gpu/drm/xe/xe_wa.h +++ b/drivers/gpu/drm/xe/xe_wa.h @@ -6,6 +6,7 @@ #ifndef _XE_WA_H_ #define _XE_WA_H_ +#include #include "xe_assert.h" struct drm_printer; @@ -24,6 +25,10 @@ void xe_wa_apply_tile_workarounds(struct xe_tile *tile); void xe_wa_device_dump(struct xe_device *xe, struct drm_printer *p); int xe_wa_gt_dump(struct xe_gt *gt, struct drm_printer *p); +#if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST) +extern const struct xe_rtp_table_sr gt_was; +#endif + /** * XE_GT_WA - Out-of-band GT workarounds, to be queried and called as needed. * @gt__: gt instance -- cgit v1.2.3 From e2cfc5bc0c3ff132cdbe29b4843836c34a38889e Mon Sep 17 00:00:00 2001 From: Violet Monti Date: Mon, 1 Jun 2026 13:09:49 -0700 Subject: drm/xe/rtp: Ensure oob_was does not evaluate engine type rules This commit builds on the implementation of the GT WA testing, increasing the scope of testing to include the OOB workaround list. The added test checks for workarounds with XE_RTP_ENGINE_CLASS() rules and raises an expectationfailure if any are found. Unlike the GT workarounds, there are no flags within this workaround list, so all invalid rules will fail. v6: - No change v5: - No change v4: - No change v3: - Removed VISIBLE_IF_KUNIT keyword from xe_wa.h - Reworked KUNIT_EXPECT_TRUE for easier decoding of errors v2: - Changed xe_rtp_table_oob_test() to follow format of xe_rtp_table_gt_test - Changed oob_was generated params to follow format of gt_was generated params Reviewed-by: Gustavo Sousa Signed-off-by: Violet Monti Link: https://patch.msgid.link/20260601200947.2032784-9-violet.monti@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c | 15 +++++++++++++++ drivers/gpu/drm/xe/xe_wa.c | 3 ++- drivers/gpu/drm/xe/xe_wa.h | 1 + 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c b/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c index 7dd77133bc42..ff6ff2d49ad7 100644 --- a/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c +++ b/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c @@ -39,9 +39,24 @@ static void xe_rtp_table_gt_test(struct kunit *test) RTP_TABLE_PARAM(gt_was); RTP_TABLE_PARAM(gt_tunings); +static void xe_rtp_table_oob_test(struct kunit *test) +{ + const struct xe_rtp_entry *entry = test->param_value; + + for (int i = 0; i < entry->n_rules; i++) { + u8 match_type = entry->rules[i].match_type; + + KUNIT_EXPECT_NE(test, match_type, XE_RTP_MATCH_ENGINE_CLASS); + KUNIT_EXPECT_NE(test, match_type, XE_RTP_MATCH_NOT_ENGINE_CLASS); + } +} + +RTP_TABLE_PARAM(oob_was); + static struct kunit_case xe_rtp_table_tests[] = { KUNIT_CASE_PARAM(xe_rtp_table_gt_test, gt_was_gen_params), KUNIT_CASE_PARAM(xe_rtp_table_gt_test, gt_tunings_gen_params), + KUNIT_CASE_PARAM(xe_rtp_table_oob_test, oob_was_gen_params), {} }; diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c index 1a1e04215f21..410099545f4e 100644 --- a/drivers/gpu/drm/xe/xe_wa.c +++ b/drivers/gpu/drm/xe/xe_wa.c @@ -803,10 +803,11 @@ static const struct xe_rtp_entry oob_was_entries[] = { static_assert(ARRAY_SIZE(oob_was_entries) == _XE_WA_OOB_COUNT); -static __maybe_unused const struct xe_rtp_table oob_was = { +VISIBLE_IF_KUNIT __maybe_unused const struct xe_rtp_table oob_was = { .entries = oob_was_entries, .n_entries = ARRAY_SIZE(oob_was_entries), }; +EXPORT_SYMBOL_IF_KUNIT(oob_was); static const struct xe_rtp_entry device_oob_was_entries[] = { #include diff --git a/drivers/gpu/drm/xe/xe_wa.h b/drivers/gpu/drm/xe/xe_wa.h index 8784b491dde7..c5cc260621cd 100644 --- a/drivers/gpu/drm/xe/xe_wa.h +++ b/drivers/gpu/drm/xe/xe_wa.h @@ -27,6 +27,7 @@ int xe_wa_gt_dump(struct xe_gt *gt, struct drm_printer *p); #if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST) extern const struct xe_rtp_table_sr gt_was; +extern __maybe_unused const struct xe_rtp_table oob_was; #endif /** -- cgit v1.2.3 From 94e15e89f491eb1c226ee996eb15cf5a15d90677 Mon Sep 17 00:00:00 2001 From: Violet Monti Date: Mon, 1 Jun 2026 13:09:50 -0700 Subject: drm/xe/rtp: Ensure device_oob_was only evaluates correct rules This commit builds on the implementation of the GT WA testing, increasing the scope of testing to include the device OOB workaround list. As well as checking for XE_RTP_ENGINE_CLASS(), this test also checks for rules involving XE_RTP_GRAPHICS() and XE_RTP_MEDIA(), as well as their derivatives. This test will raise expectation fails for any workarounds in the device_oob_was list that has an invalid rule type, preventing evaluation or inclusion of rules that could be applied in the wrong context. v6: - No change v5: - No change v4: - No change v3: - Removed "VISIBLE_IF_KUNIT" keyword from xe_wa.h - Heavily reworked rule checking within _dev_oob_test() function for easier understanding and interpreting of errors v2: - Changed xe_rtp_table_dev_oob_test() to follow format of xe_rtp_table_gt_test - Changed device_oob_was generated params to follow format of gt_was Reviewed-by: Gustavo Sousa Signed-off-by: Violet Monti Link: https://patch.msgid.link/20260601200947.2032784-10-violet.monti@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c | 23 +++++++++++++++++++++++ drivers/gpu/drm/xe/xe_wa.c | 3 ++- drivers/gpu/drm/xe/xe_wa.h | 1 + 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c b/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c index ff6ff2d49ad7..ef379cbb6a86 100644 --- a/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c +++ b/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c @@ -53,10 +53,33 @@ static void xe_rtp_table_oob_test(struct kunit *test) RTP_TABLE_PARAM(oob_was); +static void xe_rtp_table_dev_oob_test(struct kunit *test) +{ + const struct xe_rtp_entry *entry = test->param_value; + + for (int i = 0; i < entry->n_rules; i++) { + u8 match_type = entry->rules[i].match_type; + + KUNIT_EXPECT_NE(test, match_type, XE_RTP_MATCH_ENGINE_CLASS); + KUNIT_EXPECT_NE(test, match_type, XE_RTP_MATCH_NOT_ENGINE_CLASS); + KUNIT_EXPECT_NE(test, match_type, XE_RTP_MATCH_GRAPHICS_VERSION); + KUNIT_EXPECT_NE(test, match_type, XE_RTP_MATCH_GRAPHICS_VERSION_RANGE); + KUNIT_EXPECT_NE(test, match_type, XE_RTP_MATCH_GRAPHICS_VERSION_ANY_GT); + KUNIT_EXPECT_NE(test, match_type, XE_RTP_MATCH_GRAPHICS_STEP); + KUNIT_EXPECT_NE(test, match_type, XE_RTP_MATCH_MEDIA_VERSION); + KUNIT_EXPECT_NE(test, match_type, XE_RTP_MATCH_MEDIA_VERSION_RANGE); + KUNIT_EXPECT_NE(test, match_type, XE_RTP_MATCH_MEDIA_VERSION_ANY_GT); + KUNIT_EXPECT_NE(test, match_type, XE_RTP_MATCH_MEDIA_STEP); + } +} + +RTP_TABLE_PARAM(device_oob_was); + static struct kunit_case xe_rtp_table_tests[] = { KUNIT_CASE_PARAM(xe_rtp_table_gt_test, gt_was_gen_params), KUNIT_CASE_PARAM(xe_rtp_table_gt_test, gt_tunings_gen_params), KUNIT_CASE_PARAM(xe_rtp_table_oob_test, oob_was_gen_params), + KUNIT_CASE_PARAM(xe_rtp_table_dev_oob_test, device_oob_was_gen_params), {} }; diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c index 410099545f4e..635d5461f712 100644 --- a/drivers/gpu/drm/xe/xe_wa.c +++ b/drivers/gpu/drm/xe/xe_wa.c @@ -815,10 +815,11 @@ static const struct xe_rtp_entry device_oob_was_entries[] = { static_assert(ARRAY_SIZE(device_oob_was_entries) == _XE_DEVICE_WA_OOB_COUNT); -static __maybe_unused const struct xe_rtp_table device_oob_was = { +VISIBLE_IF_KUNIT __maybe_unused const struct xe_rtp_table device_oob_was = { .entries = device_oob_was_entries, .n_entries = ARRAY_SIZE(device_oob_was_entries), }; +EXPORT_SYMBOL_IF_KUNIT(device_oob_was); __diag_pop(); diff --git a/drivers/gpu/drm/xe/xe_wa.h b/drivers/gpu/drm/xe/xe_wa.h index c5cc260621cd..f4da2b271396 100644 --- a/drivers/gpu/drm/xe/xe_wa.h +++ b/drivers/gpu/drm/xe/xe_wa.h @@ -28,6 +28,7 @@ int xe_wa_gt_dump(struct xe_gt *gt, struct drm_printer *p); #if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST) extern const struct xe_rtp_table_sr gt_was; extern __maybe_unused const struct xe_rtp_table oob_was; +extern __maybe_unused const struct xe_rtp_table device_oob_was; #endif /** -- cgit v1.2.3 From 6a1e7934d9a6cf46aecae00a99c2603d1295e170 Mon Sep 17 00:00:00 2001 From: Tangudu Tilak Tirumalesh Date: Wed, 3 Jun 2026 12:22:15 +0530 Subject: Revert "drm/xe: Skip exec queue schedule toggle if queue is idle during suspend" This reverts commit 8533051ce92015e9cc6f75e0d52119b9d91610b6. The idle-skip optimization bypasses GuC suspend, so the GPU may not perform the context switch that flushes TLB entries for invalidated userptr VMAs. In LR/preempt-fence VM mode, this can lead to missed TLB invalidation and page faults during userptr invalidation tests. Restore unconditional schedule toggling on suspend so the context-switch TLB flush is always performed. This optimization will be reintroduced with a fix that does not skip suspend in LR/preempt-fence VM mode. Fixes: 8533051ce920 ("drm/xe: Skip exec queue schedule toggle if queue is idle during suspend") Cc: stable@vger.kernel.org # v7.0+ Suggested-by: Thomas Hellstrom Signed-off-by: Tangudu Tilak Tirumalesh Reviewed-by: Thomas Hellstrom Signed-off-by: Daniele Ceraolo Spurio Link: https://patch.msgid.link/20260603065217.3131066-2-tilak.tirumalesh.tangudu@intel.com --- drivers/gpu/drm/xe/xe_exec_queue.h | 17 ---------- drivers/gpu/drm/xe/xe_guc_submit.c | 55 ++------------------------------- drivers/gpu/drm/xe/xe_hw_engine_group.c | 10 ++---- 3 files changed, 5 insertions(+), 77 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_exec_queue.h b/drivers/gpu/drm/xe/xe_exec_queue.h index a82d99bd77bc..0225426c57b0 100644 --- a/drivers/gpu/drm/xe/xe_exec_queue.h +++ b/drivers/gpu/drm/xe/xe_exec_queue.h @@ -162,21 +162,4 @@ int xe_exec_queue_contexts_hwsp_rebase(struct xe_exec_queue *q, void *scratch); struct xe_lrc *xe_exec_queue_lrc(struct xe_exec_queue *q); struct xe_lrc *xe_exec_queue_get_lrc(struct xe_exec_queue *q, u16 idx); -/** - * xe_exec_queue_idle_skip_suspend() - Can exec queue skip suspend - * @q: The exec_queue - * - * If an exec queue is not parallel and is idle, the suspend steps can be - * skipped in the submission backend immediatley signaling the suspend fence. - * Parallel queues cannot skip this step due to limitations in the submission - * backend. - * - * Return: True if exec queue is idle and can skip suspend steps, False - * otherwise - */ -static inline bool xe_exec_queue_idle_skip_suspend(struct xe_exec_queue *q) -{ - return !xe_exec_queue_is_parallel(q) && xe_exec_queue_is_idle(q); -} - #endif diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index ab501513d806..d1ab66ca1856 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -71,7 +71,6 @@ exec_queue_to_guc(struct xe_exec_queue *q) #define EXEC_QUEUE_STATE_WEDGED (1 << 8) #define EXEC_QUEUE_STATE_BANNED (1 << 9) #define EXEC_QUEUE_STATE_PENDING_RESUME (1 << 10) -#define EXEC_QUEUE_STATE_IDLE_SKIP_SUSPEND (1 << 11) static bool exec_queue_registered(struct xe_exec_queue *q) { @@ -218,21 +217,6 @@ static void clear_exec_queue_pending_resume(struct xe_exec_queue *q) atomic_and(~EXEC_QUEUE_STATE_PENDING_RESUME, &q->guc->state); } -static bool exec_queue_idle_skip_suspend(struct xe_exec_queue *q) -{ - return atomic_read(&q->guc->state) & EXEC_QUEUE_STATE_IDLE_SKIP_SUSPEND; -} - -static void set_exec_queue_idle_skip_suspend(struct xe_exec_queue *q) -{ - atomic_or(EXEC_QUEUE_STATE_IDLE_SKIP_SUSPEND, &q->guc->state); -} - -static void clear_exec_queue_idle_skip_suspend(struct xe_exec_queue *q) -{ - atomic_and(~EXEC_QUEUE_STATE_IDLE_SKIP_SUSPEND, &q->guc->state); -} - static bool exec_queue_killed_or_banned_or_wedged(struct xe_exec_queue *q) { return (atomic_read(&q->guc->state) & @@ -1157,7 +1141,7 @@ static void submit_exec_queue(struct xe_exec_queue *q, struct xe_sched_job *job) if (!job->restore_replay || job->last_replay) { if (xe_exec_queue_is_parallel(q)) wq_item_append(q); - else if (!exec_queue_idle_skip_suspend(q)) + else xe_lrc_set_ring_tail(lrc, lrc->ring.tail); job->last_replay = false; } @@ -1812,10 +1796,9 @@ static void __guc_exec_queue_process_msg_suspend(struct xe_sched_msg *msg) { struct xe_exec_queue *q = msg->private_data; struct xe_guc *guc = exec_queue_to_guc(q); - bool idle_skip_suspend = xe_exec_queue_idle_skip_suspend(q); - if (!idle_skip_suspend && guc_exec_queue_allowed_to_change_state(q) && - !exec_queue_suspended(q) && exec_queue_enabled(q)) { + if (guc_exec_queue_allowed_to_change_state(q) && !exec_queue_suspended(q) && + exec_queue_enabled(q)) { wait_event(guc->ct.wq, vf_recovery(guc) || ((q->guc->resume_time != RESUME_PENDING || xe_guc_read_stopped(guc)) && !exec_queue_pending_disable(q))); @@ -1834,33 +1817,11 @@ static void __guc_exec_queue_process_msg_suspend(struct xe_sched_msg *msg) disable_scheduling(q, false); } } else if (q->guc->suspend_pending) { - if (idle_skip_suspend) - set_exec_queue_idle_skip_suspend(q); set_exec_queue_suspended(q); suspend_fence_signal(q); } } -static void sched_context(struct xe_exec_queue *q) -{ - struct xe_guc *guc = exec_queue_to_guc(q); - struct xe_lrc *lrc = q->lrc[0]; - u32 action[] = { - XE_GUC_ACTION_SCHED_CONTEXT, - q->guc->id, - }; - - xe_gt_assert(guc_to_gt(guc), !xe_exec_queue_is_parallel(q)); - xe_gt_assert(guc_to_gt(guc), !exec_queue_destroyed(q)); - xe_gt_assert(guc_to_gt(guc), exec_queue_registered(q)); - xe_gt_assert(guc_to_gt(guc), !exec_queue_pending_disable(q)); - - trace_xe_exec_queue_submit(q); - - xe_lrc_set_ring_tail(lrc, lrc->ring.tail); - xe_guc_ct_send(&guc->ct, action, ARRAY_SIZE(action), 0, 0); -} - static void __guc_exec_queue_process_msg_resume(struct xe_sched_msg *msg) { struct xe_exec_queue *q = msg->private_data; @@ -1868,22 +1829,12 @@ static void __guc_exec_queue_process_msg_resume(struct xe_sched_msg *msg) if (guc_exec_queue_allowed_to_change_state(q)) { clear_exec_queue_suspended(q); if (!exec_queue_enabled(q)) { - if (exec_queue_idle_skip_suspend(q)) { - struct xe_lrc *lrc = q->lrc[0]; - - clear_exec_queue_idle_skip_suspend(q); - xe_lrc_set_ring_tail(lrc, lrc->ring.tail); - } q->guc->resume_time = RESUME_PENDING; set_exec_queue_pending_resume(q); enable_scheduling(q); - } else if (exec_queue_idle_skip_suspend(q)) { - clear_exec_queue_idle_skip_suspend(q); - sched_context(q); } } else { clear_exec_queue_suspended(q); - clear_exec_queue_idle_skip_suspend(q); } } diff --git a/drivers/gpu/drm/xe/xe_hw_engine_group.c b/drivers/gpu/drm/xe/xe_hw_engine_group.c index 4c2b113364d3..02cf32ae5aa9 100644 --- a/drivers/gpu/drm/xe/xe_hw_engine_group.c +++ b/drivers/gpu/drm/xe/xe_hw_engine_group.c @@ -208,21 +208,15 @@ static int xe_hw_engine_group_suspend_faulting_lr_jobs(struct xe_hw_engine_group lockdep_assert_held_write(&group->mode_sem); list_for_each_entry(q, &group->exec_queue_list, hw_engine_group_link) { - bool idle_skip_suspend; if (!xe_vm_in_fault_mode(q->vm)) continue; - idle_skip_suspend = xe_exec_queue_idle_skip_suspend(q); - if (!idle_skip_suspend && has_deps) + if (has_deps) return -EAGAIN; xe_gt_stats_incr(q->gt, XE_GT_STATS_ID_HW_ENGINE_GROUP_SUSPEND_LR_QUEUE_COUNT, 1); - if (idle_skip_suspend) - xe_gt_stats_incr(q->gt, - XE_GT_STATS_ID_HW_ENGINE_GROUP_SKIP_LR_QUEUE_COUNT, 1); - - need_resume |= !idle_skip_suspend; + need_resume = true; q->ops->suspend(q); gt = q->gt; } -- cgit v1.2.3 From 4b1ae138b0e103d753773956a84eebc2edbf62c4 Mon Sep 17 00:00:00 2001 From: Tangudu Tilak Tirumalesh Date: Wed, 3 Jun 2026 12:22:16 +0530 Subject: drm/xe: Clear pending_disable before signaling suspend fence In the schedule-disable done path for suspend, we signal the suspend fence before clearing pending_disable. That wakeup can let suspend_wait complete and resume be queued immediately. The resume path may then reach enable_scheduling() while pending_disable is still set and hit the !exec_queue_pending_disable(q) assertion. Fix this by clearing pending_disable before signaling the suspend fence, so any resumed transition observes a consistent state. Fixes: 87651f31ae4e ("drm/xe/guc_submit: fix race around suspend_pending") Cc: stable@vger.kernel.org # v7.0+ Signed-off-by: Tangudu Tilak Tirumalesh Reviewed-by: Thomas Hellstrom Signed-off-by: Daniele Ceraolo Spurio Link: https://patch.msgid.link/20260603065217.3131066-3-tilak.tirumalesh.tangudu@intel.com --- drivers/gpu/drm/xe/xe_guc_submit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index d1ab66ca1856..122a0983df18 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -2791,8 +2791,8 @@ static void handle_sched_done(struct xe_guc *guc, struct xe_exec_queue *q, xe_gt_assert(guc_to_gt(guc), exec_queue_pending_disable(q)); if (q->guc->suspend_pending) { - suspend_fence_signal(q); clear_exec_queue_pending_disable(q); + suspend_fence_signal(q); } else { if (exec_queue_banned(q)) { smp_wmb(); -- cgit v1.2.3 From f22dbf90f011fa1ae0fe02841fb2676f87633783 Mon Sep 17 00:00:00 2001 From: Tangudu Tilak Tirumalesh Date: Wed, 3 Jun 2026 12:22:17 +0530 Subject: drm/xe: explicit TLB flush for context based tlb invalidation In LR preempt-fence mode, on devices with context based TLB Invalidation, rebind operations for VMAs require an explicit invalidation request. Request explicit TLB Invalidation in notifier path and in PT path. Userptr VMAs are excluded in PT path since the notifier path already submits invalidation, preventing duplicate requests for the same rebind window. v2: Remove explicit TLB Invalidation in notifier path as PT path is sufficient. Refactor of above to remove exclusion of userptr VMAs n PT path.- Thomas v3: Knit-Remove unrelated change.-Thomas Assisted-by: Claude:claude-opus-4.6 Signed-off-by: Tangudu Tilak Tirumalesh Reviewed-by: Thomas Hellstrom Signed-off-by: Daniele Ceraolo Spurio Link: https://patch.msgid.link/20260603065217.3131066-4-tilak.tirumalesh.tangudu@intel.com --- drivers/gpu/drm/xe/xe_pt.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c index 2669ff5ee747..15ce77ce7793 100644 --- a/drivers/gpu/drm/xe/xe_pt.c +++ b/drivers/gpu/drm/xe/xe_pt.c @@ -2010,6 +2010,9 @@ static int bind_op_prepare(struct xe_vm *vm, struct xe_tile *tile, * automatically when the context is re-enabled by the rebind worker, * or in fault mode it was invalidated on PTE zapping. * + * If rebind, we have to invalidate TLB on context based TLB invalidation + * LR vms, as they cannot be relied on context re-enable. + * * If !rebind, and scratch enabled VMs, there is a chance the scratch * PTE is already cached in the TLB so it needs to be invalidated. * On !LR VMs this is done in the ring ops preceding a batch, but on @@ -2019,6 +2022,9 @@ static int bind_op_prepare(struct xe_vm *vm, struct xe_tile *tile, if ((!pt_op->rebind && xe_vm_has_scratch(vm) && xe_vm_in_lr_mode(vm))) pt_update_ops->needs_invalidation = true; + else if (pt_op->rebind && xe_vm_in_preempt_fence_mode(vm) && + vm->xe->info.has_ctx_tlb_inval) + pt_update_ops->needs_invalidation = true; else if (pt_op->rebind && !xe_vm_in_lr_mode(vm)) /* We bump also if batch_invalidate_tlb is true */ vm->tlb_flush_seqno++; -- cgit v1.2.3 From 3dbb27b1db141671dd7ab2e0e0fffcea5d0fb5bc Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Thu, 21 May 2026 16:31:33 -0700 Subject: drm/xe/pxp: PXP no longer requires HuC from media 35 onwards Starting from media 35 the HuC is loaded by userspace instead of the kernel, so it is no longer considered a requirement to start a PXP session. Signed-off-by: Daniele Ceraolo Spurio Cc: Julia Filipchuk Reviewed-by: Julia Filipchuk Link: https://patch.msgid.link/20260521233132.883021-2-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/xe/xe_pxp.c | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_pxp.c b/drivers/gpu/drm/xe/xe_pxp.c index 968b7e70b3f9..fea3d8ceeddb 100644 --- a/drivers/gpu/drm/xe/xe_pxp.c +++ b/drivers/gpu/drm/xe/xe_pxp.c @@ -59,6 +59,7 @@ bool xe_pxp_is_enabled(const struct xe_pxp *pxp) static bool pxp_prerequisites_done(const struct xe_pxp *pxp) { struct xe_gt *gt = pxp->gt; + bool huc_ok; bool ready; CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FORCEWAKE_ALL); @@ -73,9 +74,14 @@ static bool pxp_prerequisites_done(const struct xe_pxp *pxp) */ XE_WARN_ON(!xe_force_wake_ref_has_domain(fw_ref.domains, XE_FORCEWAKE_ALL)); - /* PXP requires both HuC authentication via GSC and GSC proxy initialized */ - ready = xe_huc_is_authenticated(>->uc.huc, XE_HUC_AUTH_VIA_GSC) && - xe_gsc_proxy_init_done(>->uc.gsc); + /* + * PXP requires GSC proxy to be initialized. On platforms where the HuC + * is loaded by the kernel driver (i.e., pre media 35) PXP also requires + * the HuC to be authenticated by GSC. + */ + huc_ok = MEDIA_VER(gt_to_xe(gt)) >= 35 || + xe_huc_is_authenticated(>->uc.huc, XE_HUC_AUTH_VIA_GSC); + ready = huc_ok && xe_gsc_proxy_init_done(>->uc.gsc); return ready; } @@ -97,9 +103,13 @@ int xe_pxp_get_readiness_status(struct xe_pxp *pxp) if (!xe_pxp_is_enabled(pxp)) return -ENODEV; - /* if the GSC or HuC FW are in an error state, PXP will never work */ - if (xe_uc_fw_status_to_error(pxp->gt->uc.huc.fw.status) || - xe_uc_fw_status_to_error(pxp->gt->uc.gsc.fw.status)) + /* If the GSC FW is in an error state, PXP will never work */ + if (xe_uc_fw_status_to_error(pxp->gt->uc.gsc.fw.status)) + return -EIO; + + /* Same for HuC FW, but only if the kernel owns HuC-loading (i.e. pre-NVL) */ + if (MEDIA_VER(gt_to_xe(pxp->gt)) < 35 && + xe_uc_fw_status_to_error(pxp->gt->uc.huc.fw.status)) return -EIO; guard(xe_pm_runtime)(pxp->xe); @@ -361,6 +371,7 @@ static void pxp_fini(void *arg) int xe_pxp_init(struct xe_device *xe) { struct xe_gt *gt = xe->tiles[0].media_gt; + bool gsc_ok, huc_ok; struct xe_pxp *pxp; int err; @@ -375,10 +386,14 @@ int xe_pxp_init(struct xe_device *xe) if (!(gt->info.engine_mask & BIT(XE_HW_ENGINE_GSCCS0))) return 0; - /* PXP requires both GSC and HuC firmwares to be available */ - if (!xe_uc_fw_is_loadable(>->uc.gsc.fw) || - !xe_uc_fw_is_loadable(>->uc.huc.fw)) { - drm_info(&xe->drm, "skipping PXP init due to missing FW dependencies"); + /* PXP requires GSC FW to be available. Pre-NVL it also requires HuC FW */ + gsc_ok = xe_uc_fw_is_loadable(>->uc.gsc.fw); + huc_ok = MEDIA_VER(xe) >= 35 || xe_uc_fw_is_loadable(>->uc.huc.fw); + + if (!gsc_ok || !huc_ok) { + drm_info(&xe->drm, "Skipping PXP due to unsatisfied FW deps - GSC=%s, HuC=%s\n", + str_yes_no(gsc_ok), + MEDIA_VER(xe) >= 35 ? "not needed" : str_yes_no(huc_ok)); return 0; } -- cgit v1.2.3 From b7fb55cc3364ca128cfff9d50649ffd4327cd01e Mon Sep 17 00:00:00 2001 From: Niranjana Vishwanathapura Date: Wed, 3 Jun 2026 16:39:47 -0700 Subject: drm/xe/multi_queue: skip submit when primary queue is suspended Return early in submit path when the multi-queue primary exec queue is suspended to avoid submitting while suspended. v2: Remove idle_skip_suspend fix as that feature is being reverted here https://patchwork.freedesktop.org/series/167262/ Fixes: bc5775c59258 ("drm/xe/multi_queue: Add GuC interface for multi queue support") Cc: stable@vger.kernel.org # v7.0+ Assisted-by: GitHub-Copilot:claude-sonnet-4.6 Reviewed-by: Daniele Ceraolo Spurio Signed-off-by: Niranjana Vishwanathapura Link: https://patch.msgid.link/20260603233946.863663-2-niranjana.vishwanathapura@intel.com --- drivers/gpu/drm/xe/xe_guc_submit.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index 122a0983df18..4b247a3019d2 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -1151,9 +1151,12 @@ static void submit_exec_queue(struct xe_exec_queue *q, struct xe_sched_job *job) /* * All queues in a multi-queue group will use the primary queue - * of the group to interface with GuC. + * of the group to interface with GuC. If primay is suspended, + * just return. Jobs will get scheduled once primary is resumed. */ q = xe_exec_queue_multi_queue_primary(q); + if (exec_queue_suspended(q)) + return; if (!exec_queue_enabled(q) && !exec_queue_suspended(q)) { action[len++] = XE_GUC_ACTION_SCHED_CONTEXT_MODE_SET; -- cgit v1.2.3 From a57011eff45e7265dc42a7adad68b84605d8f828 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Fri, 5 Jun 2026 11:33:05 +0200 Subject: drm/xe/rtp: Fix build error with clang < 21 and non-const initializers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clang < 21 treats const-qualified compound literals at function scope as having static storage duration, which requires all initializer elements to be compile-time constants. When xe_hw_engine.c initializes a local struct xe_rtp_table_sr using XE_RTP_TABLE_SR(), the compound literals in XE_RTP_TABLE_SR end up containing runtime values (e.g. blit_cctl_val derived from gt->mocs.uc_index), triggering: xe_hw_engine.c:361: error: initializer element is not a compile-time constant xe_hw_engine.c:416: error: initializer element is not a compile-time constant ARRAY_SIZE() cannot be used as a replacement because it expands through __must_be_array() -> __BUILD_BUG_ON_ZERO_MSG() -> _Static_assert inside sizeof(struct{}), which clang < 21 also rejects in the same context. Replace ARRAY_SIZE() with an open-coded sizeof(arr)/sizeof(elem) in XE_RTP_TABLE_SR and XE_RTP_TABLE to avoid both issues. Fixes: 5ff004fdc737 ("drm/xe/rtp: Add struct types for RTP tables") Cc: Matt Roper Cc: Gustavo Sousa Cc: Violet Monti Cc: Matthew Brost Cc: Thomas Hellström Cc: Rodrigo Vivi Cc: Ashutosh Dixit Cc: intel-xe@lists.freedesktop.org Reported-by: Mark Brown Closes: https://lore.kernel.org/intel-xe/bfb0dee8-b243-47ba-a89d-71472b0d51c5@sirena.org.uk/ Assisted-by: GitHub_Copilot:claude-sonnet-4.6 Signed-off-by: Thomas Hellström Reviewed-by: Gustavo Sousa Link: https://patch.msgid.link/20260605093305.110598-1-thomas.hellstrom@linux.intel.com --- drivers/gpu/drm/xe/xe_rtp.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_rtp.h b/drivers/gpu/drm/xe/xe_rtp.h index 4e3cfd69f922..2cc65053cd07 100644 --- a/drivers/gpu/drm/xe/xe_rtp.h +++ b/drivers/gpu/drm/xe/xe_rtp.h @@ -461,14 +461,22 @@ struct xe_reg_sr; XE_RTP_PASTE_FOREACH(ACTION_, COMMA, (__VA_ARGS__)) \ } +/* + * Note: ARRAY_SIZE() cannot be used here because it expands through + * __must_be_array() -> __BUILD_BUG_ON_ZERO_MSG() -> _Static_assert inside + * sizeof(struct{}), which clang < 21 rejects when the compound literal + * contains non-compile-time-constant initializers. + */ #define XE_RTP_TABLE_SR(...) { \ .entries = (const struct xe_rtp_entry_sr[]){__VA_ARGS__}, \ - .n_entries = ARRAY_SIZE(((const struct xe_rtp_entry_sr[]){__VA_ARGS__})), \ + .n_entries = sizeof((const struct xe_rtp_entry_sr[]){__VA_ARGS__}) / \ + sizeof(struct xe_rtp_entry_sr), \ } #define XE_RTP_TABLE(...) { \ .entries = (const struct xe_rtp_entry[]){__VA_ARGS__}, \ - .n_entries = ARRAY_SIZE(((const struct xe_rtp_entry[]){__VA_ARGS__})), \ + .n_entries = sizeof((const struct xe_rtp_entry[]){__VA_ARGS__}) / \ + sizeof(struct xe_rtp_entry), \ } #define XE_RTP_PROCESS_CTX_INITIALIZER(arg__) _Generic((arg__), \ -- cgit v1.2.3 From 5e34374d65315b06c044df6a6d87b7aae0499b21 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Fri, 5 Jun 2026 10:09:52 -0400 Subject: drm/xe: improve Kconfig.profile help text for scheduler timeouts The existing help texts for the JOB_TIMEOUT, TIMESLICE and PREEMPT_TIMEOUT configs were brief and did not make the role of each symbol clear: - _MIN / _MAX: hard bounds on the per-engine-class timeout. They are enforced unconditionally by the sysfs knobs, and (for TIMESLICE, the only one exposed via the SET_PROPERTY UAPI) they also bound CAP_SYS_NICE requests when DRM_XE_ENABLE_SCHEDTIMEOUT_LIMIT is enabled. - PREEMPT_TIMEOUT: the boot-time default; the JOB_TIMEOUT and TIMESLICE defaults are hardcoded in the driver, not configured here. Rewrite the help texts to reflect this, naming the relevant sysfs knobs and UAPI property explicitly. v2: Adjusted commit message based on Sashiko's review. Assisted-by: GitHub-Copilot:claude-sonnet-4.6 Assisted-by: GitHub-Copilot:claude-opus-4.8 #v2 Reviewed-by: Paulo Zanoni Link: https://patch.msgid.link/20260605140951.958172-2-rodrigo.vivi@intel.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/Kconfig.profile | 71 ++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/xe/Kconfig.profile b/drivers/gpu/drm/xe/Kconfig.profile index 7530df998148..e07517d120e0 100644 --- a/drivers/gpu/drm/xe/Kconfig.profile +++ b/drivers/gpu/drm/xe/Kconfig.profile @@ -1,50 +1,71 @@ # SPDX-License-Identifier: GPL-2.0-only config DRM_XE_JOB_TIMEOUT_MAX - int "Default max job timeout (ms)" + int "Hard upper limit for job timeout (ms)" default 10000 # milliseconds help - Configures the default max job timeout after which job will - be forcefully taken away from scheduler. + Absolute upper bound (in milliseconds) for the per-engine-class job + timeout. This is the maximum value that can be written to the sysfs + job_timeout_ms knob, regardless of privileges. To raise this ceiling, + increase this value and rebuild the kernel. config DRM_XE_JOB_TIMEOUT_MIN - int "Default min job timeout (ms)" + int "Hard lower limit for job timeout (ms)" default 1 # milliseconds help - Configures the default min job timeout after which job will - be forcefully taken away from scheduler. + Absolute lower bound (in milliseconds) for the per-engine-class job + timeout. This is the minimum value that can be written to the sysfs + job_timeout_ms knob, regardless of privileges. + + Note: the job timeout default (5000 ms) is hardcoded in the driver + and is not configurable here. Use the sysfs job_timeout_ms knob at + runtime to change the engine-class default. config DRM_XE_TIMESLICE_MAX - int "Default max timeslice duration (us)" + int "Hard upper limit for timeslice duration (us)" default 10000000 # microseconds help - Configures the default max timeslice duration between multiple - contexts by guc scheduling. + Absolute upper bound (in microseconds) for the timeslice duration. + This caps both the sysfs timeslice_duration_us knob and the value + accepted via the DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE UAPI for + processes with CAP_SYS_NICE when DRM_XE_ENABLE_SCHEDTIMEOUT_LIMIT + is enabled. config DRM_XE_TIMESLICE_MIN - int "Default min timeslice duration (us)" + int "Hard lower limit for timeslice duration (us)" default 1 # microseconds help - Configures the default min timeslice duration between multiple - contexts by guc scheduling. + Absolute lower bound (in microseconds) for the timeslice duration. + This caps both the sysfs timeslice_duration_us knob and the value + accepted via the DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE UAPI for + processes with CAP_SYS_NICE when DRM_XE_ENABLE_SCHEDTIMEOUT_LIMIT + is enabled. config DRM_XE_PREEMPT_TIMEOUT - int "Preempt timeout (us, jiffy granularity)" + int "Default preempt timeout (us, jiffy granularity)" default 640000 # microseconds help - How long to wait (in microseconds) for a preemption event to occur - when submitting a new context. If the current context does not hit - an arbitration point and yield to HW before the timer expires, the - HW will be reset to allow the more important context to execute. + Initial per-engine-class preemption timeout (in microseconds). This + is the value the driver programs at boot; it can be changed at + runtime via the sysfs preempt_timeout_us knob. + + This is how long the driver waits for the current context to reach + an arbitration point and yield the GPU voluntarily when a + higher-priority context becomes runnable. If the context does not + yield before the timer expires, the HW is reset to allow the + higher-priority context to execute. + + The range userspace may write via sysfs is bounded by + DRM_XE_PREEMPT_TIMEOUT_MIN and DRM_XE_PREEMPT_TIMEOUT_MAX. config DRM_XE_PREEMPT_TIMEOUT_MAX - int "Default max preempt timeout (us)" + int "Hard upper limit for preempt timeout (us)" default 10000000 # microseconds help - Configures the default max preempt timeout after which context - will be forcefully taken away and higher priority context will - run. + Absolute upper bound (in microseconds) for the per-engine-class + preemption timeout. This is the maximum value that can be written to + the sysfs preempt_timeout_us knob, regardless of privileges. config DRM_XE_PREEMPT_TIMEOUT_MIN - int "Default min preempt timeout (us)" + int "Hard lower limit for preempt timeout (us)" default 1 # microseconds help - Configures the default min preempt timeout after which context - will be forcefully taken away and higher priority context will - run. + Absolute lower bound (in microseconds) for the per-engine-class + preemption timeout. This is the minimum value that can be written to + the sysfs preempt_timeout_us knob, regardless of privileges. config DRM_XE_ENABLE_SCHEDTIMEOUT_LIMIT bool "Default configuration of limitation on scheduler timeout" default y -- cgit v1.2.3 From 58d77c77ea0c5cb2b755ebe23e973c8272acd896 Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Tue, 2 Jun 2026 10:18:42 +0530 Subject: drm/xe/drm_ras: Make counter allocation drm managed cleanup_node_param() is not registered for previous node in case of counter allocation failure, which results in stale memory of previous node that isn't cleaned up on unwind. Fix this using drm managed allocation, which is guaranteed to be cleaned up on unwind. Fixes: b40db12b542f ("drm/xe/xe_drm_ras: Add support for XE DRM RAS") Signed-off-by: Raag Jadav Reviewed-by: Riana Tauro Link: https://patch.msgid.link/20260602044919.702209-3-raag.jadav@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/xe_drm_ras.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_drm_ras.c b/drivers/gpu/drm/xe/xe_drm_ras.c index c21c8b428de6..c1d5ac198a7c 100644 --- a/drivers/gpu/drm/xe/xe_drm_ras.c +++ b/drivers/gpu/drm/xe/xe_drm_ras.c @@ -80,7 +80,7 @@ static struct xe_drm_ras_counter *allocate_and_copy_counters(struct xe_device *x struct xe_drm_ras_counter *counter; int i; - counter = kcalloc(DRM_XE_RAS_ERR_COMP_MAX, sizeof(*counter), GFP_KERNEL); + counter = drmm_kcalloc(&xe->drm, DRM_XE_RAS_ERR_COMP_MAX, sizeof(*counter), GFP_KERNEL); if (!counter) return ERR_PTR(-ENOMEM); @@ -135,7 +135,6 @@ static void cleanup_node_param(struct xe_drm_ras *ras, const enum drm_xe_ras_err { struct drm_ras_node *node = &ras->node[severity]; - kfree(ras->info[severity]); ras->info[severity] = NULL; kfree(node->device_name); -- cgit v1.2.3 From 67fc5543d8274b2fcbef87734fad0469358f4478 Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Tue, 2 Jun 2026 10:18:43 +0530 Subject: drm/xe/drm_ras: Add per node cleanup action cleanup_node_param() is not registered for previous node in case of counter allocation failure, which results in stale memory of previous node that isn't cleaned up on unwind. Add per node cleanup action which guarantees cleanup on unwind and also simplifies the cleanup logic. Fixes: b40db12b542f ("drm/xe/xe_drm_ras: Add support for XE DRM RAS") Signed-off-by: Raag Jadav Reviewed-by: Riana Tauro Link: https://patch.msgid.link/20260602044919.702209-4-raag.jadav@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/xe_drm_ras.c | 58 ++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_drm_ras.c b/drivers/gpu/drm/xe/xe_drm_ras.c index c1d5ac198a7c..cd236f53699e 100644 --- a/drivers/gpu/drm/xe/xe_drm_ras.c +++ b/drivers/gpu/drm/xe/xe_drm_ras.c @@ -131,53 +131,47 @@ static int assign_node_params(struct xe_device *xe, struct drm_ras_node *node, return 0; } -static void cleanup_node_param(struct xe_drm_ras *ras, const enum drm_xe_ras_error_severity severity) +static void cleanup_node_param(struct drm_ras_node *node) { - struct drm_ras_node *node = &ras->node[severity]; - - ras->info[severity] = NULL; - kfree(node->device_name); node->device_name = NULL; } +static void cleanup_node(struct drm_device *drm, void *node) +{ + drm_ras_node_unregister(node); + cleanup_node_param(node); +} + static int register_nodes(struct xe_device *xe) { struct xe_drm_ras *ras = &xe->ras; - int i; + struct drm_ras_node *node; + int i, ret; for_each_error_severity(i) { - struct drm_ras_node *node = &ras->node[i]; - int ret; + node = &ras->node[i]; ret = assign_node_params(xe, node, i); - if (ret) { - cleanup_node_param(ras, i); - return ret; - } + if (ret) + goto free_param; ret = drm_ras_node_register(node); - if (ret) { - cleanup_node_param(ras, i); - return ret; - } + if (ret) + goto free_param; + + ret = drmm_add_action_or_reset(&xe->drm, cleanup_node, node); + if (ret) + goto null_info; } return 0; -} - -static void xe_drm_ras_unregister_nodes(struct drm_device *device, void *arg) -{ - struct xe_device *xe = arg; - struct xe_drm_ras *ras = &xe->ras; - int i; - - for_each_error_severity(i) { - struct drm_ras_node *node = &ras->node[i]; - drm_ras_node_unregister(node); - cleanup_node_param(ras, i); - } +free_param: + cleanup_node_param(node); +null_info: + ras->info[i] = NULL; + return ret; } /** @@ -206,11 +200,5 @@ int xe_drm_ras_init(struct xe_device *xe) return err; } - err = drmm_add_action_or_reset(&xe->drm, xe_drm_ras_unregister_nodes, xe); - if (err) { - drm_err(&xe->drm, "Failed to add action for Xe DRM RAS (%pe)\n", ERR_PTR(err)); - return err; - } - return 0; } -- cgit v1.2.3 From ad60a618c49fef07d1860bfb1091140d29f5eddb Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Tue, 2 Jun 2026 10:18:44 +0530 Subject: drm/xe/hw_error: Use HW_ERR prefix in log Hardware errors should be logged with HW_ERR prefix. Make them consistent with existing logs. Fixes: 01aab7e1c9d4 ("drm/xe/xe_hw_error: Add support for PVC SoC errors") Signed-off-by: Raag Jadav Reviewed-by: Riana Tauro Link: https://patch.msgid.link/20260602044919.702209-5-raag.jadav@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/xe_hw_error.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_hw_error.c b/drivers/gpu/drm/xe/xe_hw_error.c index 5135e8e4093f..4b72959b2276 100644 --- a/drivers/gpu/drm/xe/xe_hw_error.c +++ b/drivers/gpu/drm/xe/xe_hw_error.c @@ -223,9 +223,9 @@ static void log_hw_error(struct xe_tile *tile, const char *name, struct xe_device *xe = tile_to_xe(tile); if (severity == DRM_XE_RAS_ERR_SEV_CORRECTABLE) - drm_warn(&xe->drm, "%s %s detected\n", name, severity_str); + drm_warn(&xe->drm, HW_ERR "%s %s detected\n", name, severity_str); else - drm_err_ratelimited(&xe->drm, "%s %s detected\n", name, severity_str); + drm_err_ratelimited(&xe->drm, HW_ERR "%s %s detected\n", name, severity_str); } static void log_gt_err(struct xe_tile *tile, const char *name, int i, u32 err, @@ -235,10 +235,10 @@ static void log_gt_err(struct xe_tile *tile, const char *name, int i, u32 err, struct xe_device *xe = tile_to_xe(tile); if (severity == DRM_XE_RAS_ERR_SEV_CORRECTABLE) - drm_warn(&xe->drm, "%s %s detected, ERROR_STAT_GT_VECTOR%d:0x%08x\n", + drm_warn(&xe->drm, HW_ERR "%s %s detected, ERROR_STAT_GT_VECTOR%d:0x%08x\n", name, severity_str, i, err); else - drm_err_ratelimited(&xe->drm, "%s %s detected, ERROR_STAT_GT_VECTOR%d:0x%08x\n", + drm_err_ratelimited(&xe->drm, HW_ERR "%s %s detected, ERROR_STAT_GT_VECTOR%d:0x%08x\n", name, severity_str, i, err); } @@ -255,9 +255,9 @@ static void log_soc_error(struct xe_tile *tile, const char * const *reg_info, if (strcmp(name, "Undefined")) { if (severity == DRM_XE_RAS_ERR_SEV_CORRECTABLE) - drm_warn(&xe->drm, "%s SOC %s detected", name, severity_str); + drm_warn(&xe->drm, HW_ERR "%s SOC %s detected", name, severity_str); else - drm_err_ratelimited(&xe->drm, "%s SOC %s detected", name, severity_str); + drm_err_ratelimited(&xe->drm, HW_ERR "%s SOC %s detected", name, severity_str); atomic_inc(&info[index].counter); } } -- cgit v1.2.3 From ca24e8d9fa48c7c121614c1a80971aecda640674 Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Thu, 21 May 2026 15:03:59 -0300 Subject: drm/xe/nvls: Update PCI IDs Bspec has been updated with respect to NVL-S PCI IDs. Update INTEL_NVLS_IDS() accordingly. Bspec: 74201 Reviewed-by: Dnyaneshwar Bhadane Link: https://patch.msgid.link/20260521-nvl-s-update-pci-ids-v1-1-ec59e5d6bf12@intel.com Signed-off-by: Gustavo Sousa --- include/drm/intel/pciids.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/drm/intel/pciids.h b/include/drm/intel/pciids.h index e32ef763427c..dff389b56eb3 100644 --- a/include/drm/intel/pciids.h +++ b/include/drm/intel/pciids.h @@ -893,8 +893,9 @@ MACRO__(0xD741, ## __VA_ARGS__), \ MACRO__(0xD742, ## __VA_ARGS__), \ MACRO__(0xD743, ## __VA_ARGS__), \ - MACRO__(0xD744, ## __VA_ARGS__), \ - MACRO__(0xD745, ## __VA_ARGS__) + MACRO__(0xD745, ## __VA_ARGS__), \ + MACRO__(0xD74A, ## __VA_ARGS__), \ + MACRO__(0xD74B, ## __VA_ARGS__) /* CRI */ #define INTEL_CRI_IDS(MACRO__, ...) \ -- cgit v1.2.3 From aa625e1e9f0710e424fe4f0e3f032807df81b5b0 Mon Sep 17 00:00:00 2001 From: Tangudu Tilak Tirumalesh Date: Mon, 8 Jun 2026 21:57:44 +0530 Subject: drm/xe: include all registered queues in TLB invalidation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Context-based TLB invalidation currently selects only scheduling-active exec queues via q->ops->active(). During rebind flows, queues may be suspended (or transitioning through resume) while still owning valid translations, causing them to be skipped from invalidation and leading to missed TLB invalidations on LR rebinds. The underlying issue is a TOCTOU: q->guc->state bits are flipped lock-free from enable_scheduling(), disable_scheduling{,_deregister}(), the suspend/resume sched-msg handlers, handle_sched_done(), and guc_exec_queue_stop(); nothing in send_tlb_inval_ctx_ppgtt() serializes against them, so any state-based predicate can race. Include all the registered queues so that TLB invalidations are not missed. This is race-free because list membership on vm->exec_queues.list is stable under vm->exec_queues.lock held by the caller. The performance impact is expected to be minimal and harmless. If it does turn out to be a concern, we can come back with a race-safe solution to ignore certain queues. Fixes: 6cdaa5346d6f ("drm/xe: Add context-based invalidation to GuC TLB invalidation backend") Assisted-by: Claude:claude-opus-4.6 Suggested-by: Thomas Hellstrom Signed-off-by: Tangudu Tilak Tirumalesh Reviewed-by: Thomas Hellström Reviewed-by: Matthew Brost Link: https://patch.msgid.link/20260608162745.338725-2-tilak.tirumalesh.tangudu@intel.com Signed-off-by: Shuicheng Lin --- drivers/gpu/drm/xe/xe_guc_tlb_inval.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_guc_tlb_inval.c b/drivers/gpu/drm/xe/xe_guc_tlb_inval.c index ced58f46f846..cf6d106e6036 100644 --- a/drivers/gpu/drm/xe/xe_guc_tlb_inval.c +++ b/drivers/gpu/drm/xe/xe_guc_tlb_inval.c @@ -255,9 +255,8 @@ static int send_tlb_inval_ctx_ppgtt(struct xe_tlb_inval *tlb_inval, u32 seqno, #undef EXEC_QUEUE_COUNT_FULL_THRESHOLD /* - * Move exec queues to a temporary list to issue invalidations. The exec - * queue must active and a reference must be taken to prevent concurrent - * deregistrations. + * Move exec queues to a temporary list to issue invalidations. A + * reference must be taken to prevent concurrent deregistrations. * * List modification is safe because we hold 'vm->exec_queues.lock' for * reading, which prevents external modifications. Using a per-GT list @@ -266,7 +265,7 @@ static int send_tlb_inval_ctx_ppgtt(struct xe_tlb_inval *tlb_inval, u32 seqno, */ list_for_each_entry_safe(q, next, &vm->exec_queues.list[id], vm_exec_queue_link) { - if (q->ops->active(q) && xe_exec_queue_get_unless_zero(q)) { + if (xe_exec_queue_get_unless_zero(q)) { last_q = q; list_move_tail(&q->vm_exec_queue_link, &tlb_inval_list); } -- cgit v1.2.3 From 2032641f7fbaee960af1d7a968f2ff767a4fb907 Mon Sep 17 00:00:00 2001 From: Tangudu Tilak Tirumalesh Date: Mon, 8 Jun 2026 21:57:45 +0530 Subject: drm/xe: drop unused xe_exec_queue_ops::active callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit send_tlb_inval_ctx_ppgtt() was the only caller of q->ops->active(q). The per-VM exec_queue list is now walked unfiltered. With no remaining callers, drop the .active op from struct xe_exec_queue_ops along with the GuC and execlist backend implementations (guc_exec_queue_active() and execlist_exec_queue_active()). Signed-off-by: Tangudu Tilak Tirumalesh Reviewed-by: Matthew Brost Reviewed-by: Thomas Hellström Link: https://patch.msgid.link/20260608162745.338725-3-tilak.tirumalesh.tangudu@intel.com Signed-off-by: Shuicheng Lin --- drivers/gpu/drm/xe/xe_exec_queue_types.h | 2 -- drivers/gpu/drm/xe/xe_execlist.c | 7 ------- drivers/gpu/drm/xe/xe_guc_submit.c | 9 --------- 3 files changed, 18 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_exec_queue_types.h b/drivers/gpu/drm/xe/xe_exec_queue_types.h index 2f5ccf294675..d27ce24daae5 100644 --- a/drivers/gpu/drm/xe/xe_exec_queue_types.h +++ b/drivers/gpu/drm/xe/xe_exec_queue_types.h @@ -318,8 +318,6 @@ struct xe_exec_queue_ops { void (*resume)(struct xe_exec_queue *q); /** @reset_status: check exec queue reset status */ bool (*reset_status)(struct xe_exec_queue *q); - /** @active: check exec queue is active */ - bool (*active)(struct xe_exec_queue *q); }; #endif diff --git a/drivers/gpu/drm/xe/xe_execlist.c b/drivers/gpu/drm/xe/xe_execlist.c index 9fb99c038ea8..6b86b4f9cc1c 100644 --- a/drivers/gpu/drm/xe/xe_execlist.c +++ b/drivers/gpu/drm/xe/xe_execlist.c @@ -458,12 +458,6 @@ static bool execlist_exec_queue_reset_status(struct xe_exec_queue *q) return false; } -static bool execlist_exec_queue_active(struct xe_exec_queue *q) -{ - /* NIY */ - return false; -} - static const struct xe_exec_queue_ops execlist_exec_queue_ops = { .init = execlist_exec_queue_init, .kill = execlist_exec_queue_kill, @@ -476,7 +470,6 @@ static const struct xe_exec_queue_ops execlist_exec_queue_ops = { .suspend_wait = execlist_exec_queue_suspend_wait, .resume = execlist_exec_queue_resume, .reset_status = execlist_exec_queue_reset_status, - .active = execlist_exec_queue_active, }; int xe_execlist_init(struct xe_gt *gt) diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index 4b247a3019d2..b29cc08e6291 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -2220,14 +2220,6 @@ static bool guc_exec_queue_reset_status(struct xe_exec_queue *q) return exec_queue_reset(q) || exec_queue_killed_or_banned_or_wedged(q); } -static bool guc_exec_queue_active(struct xe_exec_queue *q) -{ - struct xe_exec_queue *primary = xe_exec_queue_multi_queue_primary(q); - - return exec_queue_enabled(primary) && - !exec_queue_pending_disable(primary); -} - /* * All of these functions are an abstraction layer which other parts of Xe can * use to trap into the GuC backend. All of these functions, aside from init, @@ -2247,7 +2239,6 @@ static const struct xe_exec_queue_ops guc_exec_queue_ops = { .suspend_wait = guc_exec_queue_suspend_wait, .resume = guc_exec_queue_resume, .reset_status = guc_exec_queue_reset_status, - .active = guc_exec_queue_active, }; static void guc_exec_queue_stop(struct xe_guc *guc, struct xe_exec_queue *q) -- cgit v1.2.3 From 98c4a4201290823c2c5c7ba21692bd9a64b61021 Mon Sep 17 00:00:00 2001 From: Wentao Liang Date: Wed, 10 Jun 2026 10:27:05 -0700 Subject: drm/xe: fix refcount leak in xe_range_fence_insert() xe_range_fence_insert() acquires a reference on fence via dma_fence_get() and stores it in rfence->fence. It then calls dma_fence_add_callback() and handles two cases: when the callback is successfully registered (err == 0) the fence is transferred to the tree for later cleanup; when the fence is already signaled (err == -ENOENT) it manually drops the extra reference with dma_fence_put(fence). However, dma_fence_add_callback() can fail with other errors (e.g. -EINVAL) and in that case the code falls through to the free: label without releasing the acquired reference, leaking it. Fix the leak by adding an else branch that calls dma_fence_put() before jumping to free: for any error other than -ENOENT. Fixes: 845f64bdbfc9 ("drm/xe: Introduce a range-fence utility") Signed-off-by: Wentao Liang Reviewed-by: Matthew Brost Signed-off-by: Matthew Brost Link: https://patch.msgid.link/20260610172705.3450560-1-matthew.brost@intel.com --- drivers/gpu/drm/xe/xe_range_fence.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_range_fence.c b/drivers/gpu/drm/xe/xe_range_fence.c index 372378e89e98..3d8fa194a7b0 100644 --- a/drivers/gpu/drm/xe/xe_range_fence.c +++ b/drivers/gpu/drm/xe/xe_range_fence.c @@ -77,6 +77,8 @@ int xe_range_fence_insert(struct xe_range_fence_tree *tree, } else if (err == 0) { xe_range_fence_tree_insert(rfence, &tree->root); return 0; + } else { + dma_fence_put(fence); } free: -- cgit v1.2.3 From 134377098b9c14abd31c3bcac00c9653f0f0c4c3 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Tue, 26 May 2026 19:24:47 +0530 Subject: drm/xe/madvise: Skip invalidation for purgeable state updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Purgeable state updates only change VMA/BO metadata. They do not zap PTEs when switching between DONTNEED and WILLNEED. PTEs are zapped later if the BO is actually purged. xe_vm_invalidate_madvise_range() waits on the VM dma-resv before checking vma->skip_invalidation. Since purgeable madvise marks all affected VMAs to skip invalidation, this wait is unnecessary and can stall on unrelated in-flight work. Skip the invalidate path entirely for purgeable state updates. v2: - Replace inline 'args->type != DRM_XE_VMA_ATTR_PURGEABLE_STATE' check with a small helper madvise_range_needs_invalidation(). (Himal) Suggested-by: Matthew Brost Cc: Matthew Brost Cc: Thomas Hellström Cc: Himal Prasad Ghimiray Signed-off-by: Arvind Yadav Reviewed-by: Himal Prasad Ghimiray Link: https://patch.msgid.link/20260526135447.2973029-1-arvind.yadav@intel.com Signed-off-by: Tejas Upadhyay --- drivers/gpu/drm/xe/xe_vm_madvise.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_vm_madvise.c b/drivers/gpu/drm/xe/xe_vm_madvise.c index c4fb29004195..9e343f9aa44d 100644 --- a/drivers/gpu/drm/xe/xe_vm_madvise.c +++ b/drivers/gpu/drm/xe/xe_vm_madvise.c @@ -332,6 +332,20 @@ static int xe_vm_invalidate_madvise_range(struct xe_vm *vm, u64 start, u64 end) return err; } +/** + * madvise_range_needs_invalidation() - Check whether madvise needs invalidation + * @args: madvise ioctl arguments + * + * Purgeable state updates only touch VMA/BO metadata. PTEs stay valid and are + * zapped only if the BO is later purged. + * + * Return: true when the update needs PTE invalidation. + */ +static bool madvise_range_needs_invalidation(const struct drm_xe_madvise *args) +{ + return args->type != DRM_XE_VMA_ATTR_PURGEABLE_STATE; +} + static bool madvise_args_are_sane(struct xe_device *xe, const struct drm_xe_madvise *args) { if (XE_IOCTL_DBG(xe, !args)) @@ -708,8 +722,9 @@ int xe_vm_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *fil madvise_funcs[attr_type](xe, vm, madvise_range.vmas, madvise_range.num_vmas, args, &details); - err = xe_vm_invalidate_madvise_range(vm, madvise_range.addr, - madvise_range.addr + args->range); + if (madvise_range_needs_invalidation(args)) + err = xe_vm_invalidate_madvise_range(vm, madvise_range.addr, + madvise_range.addr + args->range); if (madvise_range.has_svm_userptr_vmas) xe_svm_notifier_unlock(vm); -- cgit v1.2.3 From b1107d085e7e8ed15ba6f80c102528a9c8a6cb0e Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Wed, 10 Jun 2026 11:25:49 -0400 Subject: drm/xe: fix job timeout recovery for unstarted jobs and kernel queues A job that GuC never scheduled (never started) indicates a GuC scheduling failure; previously such jobs were silently errored out instead of triggering a GT reset to recover. Trigger a GT reset and resubmit them, but only when the queue was not already killed or banned: an unstarted job on an already banned queue is the ban working as intended and must neither clear the ban nor kick off a reset, otherwise a banned userspace queue could be resurrected and spam GT resets. Kernel queues are always recovered this way and wedge the device once recovery attempts are exhausted, since kernel work must not silently fail. A started job that times out on a userspace VM bind queue stays banned rather than being reset and retried. The queue is banned early in the timeout handler to signal the G2H scheduling-done handler so it wakes the disable-scheduling waiter; without it the waiter sleeps the full 5s timeout. When a reset is warranted the ban is cleared before rearming so that guc_exec_queue_start() can resubmit jobs after the GT reset - a still-banned queue would block resubmission and cause an infinite TDR loop. The already-banned case is gated out before this point via skip_timeout_check, so it is unaffected. v2: (Himal) Do it for any queue type, not just kernel/migration v3: - (Sashiko and Sanjay): don't clear the ban / GT reset for already killed/banned queues on unstarted-job timeout - Update commit message - (Matt) Add Fixes tag Fixes: fe05cee4d953 ("drm/xe: Don't short circuit TDR on jobs not started") Cc: Matthew Auld Cc: Matthew Brost Cc: Sanjay Yadav Cc: Himal Prasad Ghimiray Assisted-by: GitHub-Copilot:claude-sonnet-4.6 Assisted-by: GitHub-Copilot:claude-opus-4.8 Tested-by: Sanjay Yadav Reviewed-by: Sanjay Yadav Reviewed-by: Matthew Brost Reviewed-by: Himal Prasad Ghimiray Link: https://patch.msgid.link/20260610152548.404575-3-rodrigo.vivi@intel.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_guc_submit.c | 49 +++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index b29cc08e6291..e82018445b7c 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -157,6 +157,11 @@ static void set_exec_queue_banned(struct xe_exec_queue *q) atomic_or(EXEC_QUEUE_STATE_BANNED, &q->guc->state); } +static void clear_exec_queue_banned(struct xe_exec_queue *q) +{ + atomic_andnot(EXEC_QUEUE_STATE_BANNED, &q->guc->state); +} + static bool exec_queue_suspended(struct xe_exec_queue *q) { return atomic_read(&q->guc->state) & EXEC_QUEUE_STATE_SUSPENDED; @@ -1363,7 +1368,8 @@ static bool check_timeout(struct xe_exec_queue *q, struct xe_sched_job *job) xe_sched_job_seqno(job), xe_sched_job_lrc_seqno(job), q->guc->id); - return xe_sched_invalidate_job(job, 2); + /* GuC never scheduled this job - let the caller trigger a GT reset. */ + return true; } ctx_timestamp = lower_32_bits(xe_lrc_timestamp(q->lrc[0])); @@ -1460,6 +1466,21 @@ static void disable_scheduling(struct xe_exec_queue *q, bool immediate) G2H_LEN_DW_SCHED_CONTEXT_MODE_SET, 1); } +/* + * Recover via GT reset for a kernel queue, or for a GuC scheduling failure (job + * never started) on a queue that was not already killed or banned. An already + * banned queue must stay banned, so its unstarted jobs do not clear the ban or + * trigger a reset. + */ +static bool timeout_needs_gt_reset(struct xe_exec_queue *q, struct xe_sched_job *job, + bool skip_timeout_check) +{ + if (q->flags & EXEC_QUEUE_FLAG_KERNEL) + return true; + + return !skip_timeout_check && !xe_sched_job_started(job); +} + static enum drm_gpu_sched_stat guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) { @@ -1608,19 +1629,19 @@ trigger_reset: xe_sched_job_seqno(job), xe_sched_job_lrc_seqno(job), q->guc->id, q->flags); - /* - * Kernel jobs should never fail, nor should VM jobs if they do - * somethings has gone wrong and the GT needs a reset - */ - xe_gt_WARN(q->gt, q->flags & EXEC_QUEUE_FLAG_KERNEL, - "Kernel-submitted job timed out\n"); - xe_gt_WARN(q->gt, q->flags & EXEC_QUEUE_FLAG_VM && !exec_queue_killed(q), - "VM job timed out on non-killed execqueue\n"); - if (!wedged && (q->flags & EXEC_QUEUE_FLAG_KERNEL || - (q->flags & EXEC_QUEUE_FLAG_VM && !exec_queue_killed(q)))) { - if (!xe_sched_invalidate_job(job, 2)) { - xe_gt_reset_async(q->gt); - goto rearm; + if (!wedged) { + if (timeout_needs_gt_reset(q, job, skip_timeout_check)) { + if (!xe_sched_invalidate_job(job, 2)) { + clear_exec_queue_banned(q); + xe_gt_reset_async(q->gt); + goto rearm; + } + if (q->flags & EXEC_QUEUE_FLAG_KERNEL) { + xe_gt_WARN(q->gt, true, "Kernel-submitted job timed out\n"); + xe_device_declare_wedged(gt_to_xe(q->gt)); + } + } else if (q->flags & EXEC_QUEUE_FLAG_VM && !exec_queue_killed(q)) { + xe_gt_WARN(q->gt, true, "VM job timed out on non-killed execqueue\n"); } } -- cgit v1.2.3 From 0cfa716f19c046b2862eb758200965c5b77b4dce Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Wed, 10 Jun 2026 11:25:50 -0400 Subject: drm/xe/lrc: fix spurious warning when reading context timestamp Fixes the following warning that fires during timeout handling for a context running on the USM-reserved copy engine: xe 0000:03:00.0: [drm] Tile0: GT0: Unexpected engine class:instance 3:8 for utilization WARNING: at engine_id_to_hwe+0x88/0xc0 [xe] xe_lrc_context_timestamp+0x61/0xb0 [xe] guc_exec_queue_timedout_job+0x713/0x1020 [xe] class:instance 3:8 is XE_ENGINE_CLASS_COPY on the highest BCS instance, which xe_hw_engine.c reserves for USM (gt->usm.reserved_bcs_instance) and on which the migrate engine runs kernel contexts. When such a context's utilization is read - e.g. from the TDR path - engine_id_to_hwe() rejected it because xe_hw_engine_is_reserved() is true, firing WARN_ONCE and returning NULL, which made the timestamp read silently fall back to stale data. The reserved-engine guard was added defensively with the original WA BB utilization support and simply overlooked that the migrate engine is a valid, present engine whose CTX_TIMESTAMP can legitimately be read. Allow the USM-reserved copy engine specifically (xe_gt_is_usm_hwe()), while still rejecting the other reserved cases (GSCCS / XE_ENGINE_CLASS_ OTHER and ccs_mode-disabled compute engines), which would indeed be unexpected on this path. The dynamic engine resolution via the ENGINE_ID stashed in the PPHWSP by the WA BB is kept intact, so utilization for load-balanced/virtual exec queues still resolves the engine the context is actually running on. Cc: Matthew Auld Cc: Matthew Brost Cc: Sanjay Yadav Cc: Himal Prasad Ghimiray Assisted-by: GitHub-Copilot:claude-sonnet-4.6 Assisted-by: GitHub-Copilot:claude-opus-4.8 Reviewed-by: Himal Prasad Ghimiray Link: https://patch.msgid.link/20260610152548.404575-4-rodrigo.vivi@intel.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_lrc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c index a4292a11391d..3e7c995085d0 100644 --- a/drivers/gpu/drm/xe/xe_lrc.c +++ b/drivers/gpu/drm/xe/xe_lrc.c @@ -2618,13 +2618,19 @@ void xe_lrc_snapshot_free(struct xe_lrc_snapshot *snapshot) kfree(snapshot); } +static bool engine_valid_for_utilization(struct xe_gt *gt, struct xe_hw_engine *hwe) +{ + /* The USM-reserved copy engine runs kernel migrate contexts queried here */ + return hwe && (!xe_hw_engine_is_reserved(hwe) || xe_gt_is_usm_hwe(gt, hwe)); +} + static struct xe_hw_engine *engine_id_to_hwe(struct xe_gt *gt, u32 engine_id) { u16 class = REG_FIELD_GET(ENGINE_CLASS_ID, engine_id); u16 instance = REG_FIELD_GET(ENGINE_INSTANCE_ID, engine_id); struct xe_hw_engine *hwe = xe_gt_hw_engine(gt, class, instance, false); - if (xe_gt_WARN_ONCE(gt, !hwe || xe_hw_engine_is_reserved(hwe), + if (xe_gt_WARN_ONCE(gt, !engine_valid_for_utilization(gt, hwe), "Unexpected engine class:instance %d:%d for utilization\n", class, instance)) return NULL; -- cgit v1.2.3 From 3a11a63cc16660d514ff584e7551589655337e87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Thu, 4 Jun 2026 09:45:00 +0200 Subject: drm/xe: Fix wa_oob codegen recipe for external module builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When building with 'make M=drivers/gpu/drm/xe modules', kbuild invokes scripts/Makefile.build with obj=., causing $(obj) to expand to '.'. Make normalizes './xe_gen_wa_oob' to 'xe_gen_wa_oob' when constructing the $^ automatic variable (target name normalization), so the recipe command becomes just 'xe_gen_wa_oob ...' without any path prefix, and the shell cannot find the tool. Fix by replacing $^ with explicit $(obj)/xe_gen_wa_oob and $(src)/ references in both wa_oob recipe commands. In recipe strings, make does not apply target name normalization, so $(obj)/xe_gen_wa_oob correctly expands to './xe_gen_wa_oob' and the shell can execute it. This matches the pattern already used by other DRM drivers (e.g. radeon's mkregtable). Fixes: f037e0b78e6d ("drm/xe: add xe_device_wa infrastructure") Cc: Matt Atwood Cc: Matthew Brost Cc: Rodrigo Vivi Cc: intel-xe@lists.freedesktop.org Assisted-by: GitHub_Copilot:claude-sonnet-4.6 Signed-off-by: Thomas Hellström Reviewed-by: Rodrigo Vivi Link: https://patch.msgid.link/20260604074501.172129-1-thomas.hellstrom@linux.intel.com --- drivers/gpu/drm/xe/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 09661f079d03..8e7b146880f4 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -16,14 +16,14 @@ subdir-ccflags-y += -I$(obj) -I$(src) hostprogs := xe_gen_wa_oob generated_oob := $(obj)/generated/xe_wa_oob.c $(obj)/generated/xe_wa_oob.h quiet_cmd_wa_oob = GEN $(notdir $(generated_oob)) - cmd_wa_oob = mkdir -p $(@D); $^ $(generated_oob) + cmd_wa_oob = mkdir -p $(@D); $(obj)/xe_gen_wa_oob $(src)/xe_wa_oob.rules $(generated_oob) $(obj)/generated/%_wa_oob.c $(obj)/generated/%_wa_oob.h: $(obj)/xe_gen_wa_oob \ $(src)/xe_wa_oob.rules $(call cmd,wa_oob) generated_device_oob := $(obj)/generated/xe_device_wa_oob.c $(obj)/generated/xe_device_wa_oob.h quiet_cmd_device_wa_oob = GEN $(notdir $(generated_device_oob)) - cmd_device_wa_oob = mkdir -p $(@D); $^ $(generated_device_oob) + cmd_device_wa_oob = mkdir -p $(@D); $(obj)/xe_gen_wa_oob $(src)/xe_device_wa_oob.rules $(generated_device_oob) $(obj)/generated/%_device_wa_oob.c $(obj)/generated/%_device_wa_oob.h: $(obj)/xe_gen_wa_oob \ $(src)/xe_device_wa_oob.rules $(call cmd,device_wa_oob) -- cgit v1.2.3 From 9f89a6de30f74db97b3f36797a0cabe057b06c2a Mon Sep 17 00:00:00 2001 From: Xin Wang Date: Thu, 4 Jun 2026 22:19:44 -0700 Subject: drm/xe/query: Avoid global forcewake in cycle query path Engine cycle query is a lightweight timestamp path and should not wake unrelated GT domains. Limit forcewake scope to what the query actually needs. Suggested-by: Matt Roper Signed-off-by: Xin Wang Reviewed-by: Matt Roper Link: https://patch.msgid.link/20260605051944.1541085-1-x.wang@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/xe_query.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_query.c b/drivers/gpu/drm/xe/xe_query.c index 8c7d54498f38..dc975f595368 100644 --- a/drivers/gpu/drm/xe/xe_query.c +++ b/drivers/gpu/drm/xe/xe_query.c @@ -119,6 +119,7 @@ query_engine_cycles(struct xe_device *xe, struct drm_xe_engine_class_instance *eci; struct drm_xe_query_engine_cycles resp; size_t size = sizeof(resp); + enum xe_force_wake_domains fw_domain; __ktime_func_t cpu_clock; struct xe_hw_engine *hwe; struct xe_gt *gt; @@ -154,8 +155,10 @@ query_engine_cycles(struct xe_device *xe, if (!hwe) return -EINVAL; - xe_with_force_wake(fw_ref, gt_to_fw(gt), XE_FORCEWAKE_ALL) { - if (!xe_force_wake_ref_has_domain(fw_ref.domains, XE_FORCEWAKE_ALL)) + fw_domain = xe_hw_engine_to_fw_domain(hwe); + + xe_with_force_wake(fw_ref, gt_to_fw(gt), fw_domain) { + if (!xe_force_wake_ref_has_domain(fw_ref.domains, fw_domain)) return -EIO; hwe_read_timestamp(hwe, &resp.engine_cycles, &resp.cpu_timestamp, -- cgit v1.2.3 From 02b41333f48748dff48e7b7ed92d9f11721e7c91 Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Wed, 10 Jun 2026 18:20:47 -0300 Subject: drm/xe/xe3p_lpg: Add missing references to workarounds Sometimes the same workaround implementation ends up being the recommended fix different hardware issues, which are tracked by different workaround lineage numbers. Some of the Xe3p_LPG workarounds got "dismissed" because the implementations were already in the driver, however for a different lineage number. Even though the implementation for workaround #A is already present in the driver for workaround #B, it is still important to reference #A in the driver for tracking purposes. Without such a reference, we risk dropping the workaround implementation if, for some reason in the future, we decide that #B is not necessary anymore while #A is still required. As such, add the missing references for Xe3p_LPG. Reviewed-by: Matt Roper Link: https://patch.msgid.link/20260610-add-missing-wa-references-v1-1-0947577238bf@intel.com Signed-off-by: Gustavo Sousa --- drivers/gpu/drm/xe/xe_wa.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c index 635d5461f712..139434946f8f 100644 --- a/drivers/gpu/drm/xe/xe_wa.c +++ b/drivers/gpu/drm/xe/xe_wa.c @@ -293,7 +293,7 @@ VISIBLE_IF_KUNIT const struct xe_rtp_table_sr gt_was = XE_RTP_TABLE_SR( XE_RTP_ACTIONS(SET(MMIOATSREQLIMIT_GAM_WALK_3D, DIS_ATS_WRONLY_PG)) }, - { XE_RTP_NAME("14026144927, 16029437861"), + { XE_RTP_NAME("14026144927, 16029437861, 14026127056"), XE_RTP_RULES(GRAPHICS_VERSION(3510), GRAPHICS_STEP(A0, B0)), XE_RTP_ACTIONS(SET(L3SQCREG2, L3_SQ_DISABLE_COAMA_2WAY_COH | L3_SQ_DISABLE_COAMA)) @@ -587,12 +587,12 @@ static const struct xe_rtp_table_sr engine_was = XE_RTP_TABLE_SR( /* Xe3p_LPG*/ - { XE_RTP_NAME("22021149932"), + { XE_RTP_NAME("22021149932, 14026290593"), XE_RTP_RULES(GRAPHICS_VERSION(3510), GRAPHICS_STEP(A0, B0), FUNC(xe_rtp_match_first_render_or_compute)), XE_RTP_ACTIONS(SET(LSC_CHICKEN_BIT_0_UDW, SAMPLER_LD_LSC_DISABLE)) }, - { XE_RTP_NAME("14025676848"), + { XE_RTP_NAME("14025676848, 14026270459"), XE_RTP_RULES(GRAPHICS_VERSION(3510), GRAPHICS_STEP(A0, B0), FUNC(xe_rtp_match_first_render_or_compute)), XE_RTP_ACTIONS(SET(LSC_CHICKEN_BIT_0_UDW, LSCFE_SAME_ADDRESS_ATOMICS_COALESCING_DISABLE)) -- cgit v1.2.3 From a889e9b06bfdb375fc88b3b2a4b143f621f930c6 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Fri, 12 Jun 2026 12:24:15 -0400 Subject: drm/xe: wedge from the timeout handler only after releasing the queue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A kernel job that exhausts its recovery attempts called xe_device_declare_wedged() directly from guc_exec_queue_timedout_job(), while the handler still owned the timed-out job and the queue scheduler (sched = &q->guc->sched, stopped at the top of the handler). In the default wedged mode (XE_WEDGED_MODE_UPON_CRITICAL_ERROR), xe_device_declare_wedged() takes the destructive path in xe_guc_submit_wedge(): guc_submit_reset_prepare(), xe_guc_submit_stop() - which calls guc_exec_queue_stop() on every queue, including this one - softreset and pause-abort. That tears submission down, signals the in-flight fences and restarts the schedulers. This is the correct behaviour when the wedge originates outside the TDR, but not when the TDR itself triggers it: every queue should be torn down except the one the TDR is currently operating on, which it still owns. Control then returned to the handler, which kept using the now stale job and scheduler: xe_sched_job_set_error(job, err); drm_sched_for_each_pending_job(tmp_job, &sched->base, NULL) xe_sched_job_set_error(to_xe_sched_job(tmp_job), -ECANCELED); drm_sched_for_each_pending_job() warns because the scheduler is no longer stopped (WARN_ON(!drm_sched_is_stopped())) and the iteration then dereferences a freed job, faulting on the slab poison: Oops: general protection fault ... 0x6b6b6b6b6b6b6c3b RIP: guc_exec_queue_timedout_job+... Defer the wedge until the handler has finished operating on the queue, right before returning DRM_GPU_SCHED_STAT_NO_HANG, so the teardown no longer races with this handler's use of @q. Fixes: b1107d085e7e ("drm/xe: fix job timeout recovery for unstarted jobs and kernel queues") Suggested-by: Matthew Brost Cc: Matthew Brost Cc: Thomas Hellström Cc: Himal Prasad Ghimiray Cc: Sanjay Yadav Assisted-by: GitHub-Copilot:claude-opus-4.8 Reviewed-by: Matthew Brost Link: https://patch.msgid.link/20260612162414.287971-2-rodrigo.vivi@intel.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_guc_submit.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index e82018445b7c..afe5d99cdd8b 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -1493,7 +1493,7 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) struct xe_device *xe = guc_to_xe(guc); int err = -ETIME; pid_t pid = -1; - bool wedged = false, skip_timeout_check; + bool wedged = false, wedge_device = false, skip_timeout_check; xe_gt_assert(guc_to_gt(guc), !exec_queue_destroyed(q)); @@ -1638,7 +1638,7 @@ trigger_reset: } if (q->flags & EXEC_QUEUE_FLAG_KERNEL) { xe_gt_WARN(q->gt, true, "Kernel-submitted job timed out\n"); - xe_device_declare_wedged(gt_to_xe(q->gt)); + wedge_device = true; } } else if (q->flags & EXEC_QUEUE_FLAG_VM && !exec_queue_killed(q)) { xe_gt_WARN(q->gt, true, "VM job timed out on non-killed execqueue\n"); @@ -1658,6 +1658,9 @@ trigger_reset: xe_guc_exec_queue_trigger_cleanup(q); } + if (wedge_device) + xe_device_declare_wedged(gt_to_xe(q->gt)); + /* * We want the job added back to the pending list so it gets freed; this * is what DRM_GPU_SCHED_STAT_NO_HANG does. -- cgit v1.2.3 From 02b7f6c326b7283fec94e44f9118a791a2477bf3 Mon Sep 17 00:00:00 2001 From: Nitin Gote Date: Thu, 11 Jun 2026 21:58:29 +0530 Subject: drm/xe/xe3: Apply Wa_16029380221 to media Apply Wa_16029380221 to Xe3p_LPM. The Xe3p_LPM media page walker is hard-wired NonCoherent and cannot observe CPU:WB cached page table data. Force page tables to CPU:WC by clearing has_cached_pt when MEDIA_VERSION(3500) is detected. v2: Simplify code comment to avoid duplicating information already present in xe_wa_oob.rules. (Gustavo) Cc: Matt Roper Reviewed-by: Gustavo Sousa Signed-off-by: Nitin Gote Link: https://patch.msgid.link/20260611162828.3879694-2-nitin.r.gote@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/xe_device.c | 9 +++++++++ drivers/gpu/drm/xe/xe_wa_oob.rules | 1 + 2 files changed, 10 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index d224861b6f6f..f73d407e1e7f 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -948,6 +948,15 @@ int xe_device_probe(struct xe_device *xe) return err; } + /* + * Wa_16029380221: The affected GT will always use non-coherent + * access to page tables, so we must do uncached writes from the + * CPU. + */ + for_each_gt(gt, xe, id) + if (XE_GT_WA(gt, 16029380221)) + xe->info.has_cached_pt = false; + for_each_tile(tile, xe, id) { err = xe_ggtt_init_early(tile->mem.ggtt); if (err) diff --git a/drivers/gpu/drm/xe/xe_wa_oob.rules b/drivers/gpu/drm/xe/xe_wa_oob.rules index f8a185103b80..9027365f0043 100644 --- a/drivers/gpu/drm/xe/xe_wa_oob.rules +++ b/drivers/gpu/drm/xe/xe_wa_oob.rules @@ -65,3 +65,4 @@ 14025883347 MEDIA_VERSION_RANGE(1301, 3503) GRAPHICS_VERSION_RANGE(2004, 3005) +16029380221 MEDIA_VERSION(3500) -- cgit v1.2.3 From 0d81db90d364cb3d733410829118759f28957c5a Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 11 Jun 2026 16:58:44 -0700 Subject: drm/xe: Set TTM device beneficial_order to 9 (2M) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set the TTM device beneficial_order to 9 (2M), which is the sweet spot for Xe when attempting reclaim on system memory BOs, as it matches the large GPU page size. This ensures reclaim is attempted at the most effective order for the driver. This fixes an issue where an order-10 (4M) allocation cannot be found despite an abundance of memory. The 4M allocation triggers reclaim, unnecessarily evicting the working set and hurting performance. Since the TTM infrastructure was introduced recently, we are tagging the TTM patch as the Fixes target, even though this resolves an Xe-side problem. Fixes: 7e9c548d3709 ("drm/ttm: Allow drivers to specify maximum beneficial TTM pool size") Cc: stable@vger.kernel.org Signed-off-by: Matthew Brost Reviewed-by: Andi Shyti Reviewed-by: Thomas Hellström Link: https://patch.msgid.link/20260611235844.3725147-1-matthew.brost@intel.com --- drivers/gpu/drm/xe/xe_device.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index f73d407e1e7f..ef730f2bdf32 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -526,7 +526,8 @@ int xe_device_init_early(struct xe_device *xe) err = ttm_device_init(&xe->ttm, &xe_ttm_funcs, xe->drm.dev, xe->drm.anon_inode->i_mapping, - xe->drm.vma_offset_manager, 0); + xe->drm.vma_offset_manager, + TTM_ALLOCATION_POOL_BENEFICIAL_ORDER(get_order(SZ_2M))); if (err) return err; -- cgit v1.2.3 From 0a78a44f4901aa6c9263e66be7fce02282f1109f Mon Sep 17 00:00:00 2001 From: Tejas Upadhyay Date: Fri, 12 Jun 2026 12:34:02 +0530 Subject: drm/xe/guc: Fix buffer overflow in steered register list allocation The size calculation for the steered register extarray uses only the geometry DSS mask (g_dss_mask) to determine the number of entries to allocate: total = bitmap_weight(gt->fuse_topo.g_dss_mask, ...) * steer_reg_num; However, the filling loop uses for_each_dss_steering(), which iterates over for_each_dss(), defined as the union of g_dss_mask and c_dss_mask (geometry + compute DSS). On platforms with compute-only DSS bits, the loop writes past the allocated buffer, corrupting adjacent slab objects. This manifests as list_del corruption and SLUB redzone overwrites during drm_managed_release on device unbind, since the overflow corrupts the drmres list_head of neighboring allocations. Fix by computing the allocation size using the union of both DSS masks, matching the iteration pattern of for_each_dss_steering(). -- v2: - use bitmap_weighted_or() (Zhanjun) Fixes: b170d696c1e2 ("drm/xe/guc: Add XE_LP steered register lists") Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/8049 Cc: Zhanjun Dong Cc: stable@vger.kernel.org Assisted-by: GitHub-Copilot:claude-opus-4.6 Reviewed-by: Zhanjun Dong Link: https://patch.msgid.link/20260612070401.543305-2-tejas.upadhyay@intel.com Signed-off-by: Tejas Upadhyay --- drivers/gpu/drm/xe/xe_guc_capture.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_guc_capture.c b/drivers/gpu/drm/xe/xe_guc_capture.c index 21f7caf9ea08..1a019137ddf4 100644 --- a/drivers/gpu/drm/xe/xe_guc_capture.c +++ b/drivers/gpu/drm/xe/xe_guc_capture.c @@ -461,8 +461,14 @@ static void guc_capture_alloc_steered_lists(struct xe_guc *guc) if (!list || guc->capture->extlists) return; - total = bitmap_weight(gt->fuse_topo.g_dss_mask, sizeof(gt->fuse_topo.g_dss_mask) * 8) * - guc_capture_get_steer_reg_num(guc_to_xe(guc)); + { + xe_dss_mask_t all_dss; + + total = bitmap_weighted_or(all_dss, gt->fuse_topo.g_dss_mask, + gt->fuse_topo.c_dss_mask, + XE_MAX_DSS_FUSE_BITS) * + guc_capture_get_steer_reg_num(guc_to_xe(guc)); + } if (!total) return; -- cgit v1.2.3 From 669252801a4aa4098fbc5dd9dd0bd93f0625abd7 Mon Sep 17 00:00:00 2001 From: Brian Nguyen Date: Fri, 5 Jun 2026 22:42:58 +0000 Subject: drm/xe: Add compact-PT and addr mask handling for page reclaim Current implementation of generate_reclaim_entry() overlooks some differences between the different page implementations: address masking and compact 64K page handling. Address masking of each leaf varies depending on the leaf entry size. generate_reclaim_entry() is using XE_PTE_ADDR_MASK [51:12] for all leaf entries. For 2MB PTEs, bit 12 (PAT) is part of the flags so the old mask corrupts the physical address extraction. 64K pages can be represented as PS64 and a compact PT, which the latter was not handled. Compact pages aren't walked by the unbind walker, so we separately walk through the compact PT to ensure none of the leaf 64K PTEs are dropped. Previously, compact PT were causing an abort since it was considered covered and not descended into. v2: - Update 64K entry/unbind walker for 64K compact PT handling. (Matthew) - Rework calculations of reclamation and address mask size. - Add new func abstracting the error handling before generating the reclaim entry. v3: - Report finer addr granularity in abort debug print for compact. (Zongyao) - Add comments for ADDR_MASK usage. (Zongyao) - Drop existing phys_addr asserts, the new XE_PAGE_ADDR_MASK clears bits checked, so redundant asserts. (Sashiko) - WARN_ON to verify compact pt and edge pt won't be possible. Fixes: b912138df299 ("drm/xe: Create page reclaim list on unbind") Assisted-by: Sashiko-Review:gemini-3.1-pro-preview Cc: stable@vger.kernel.org Cc: Matthew Auld Suggested-by: Zongyao Bai Signed-off-by: Brian Nguyen Reviewed-by: Matthew Auld Reviewed-by: Zongyao Bai Link: https://patch.msgid.link/20260605224257.2194194-2-brian3.nguyen@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/regs/xe_gtt_defs.h | 6 +- drivers/gpu/drm/xe/xe_pt.c | 133 ++++++++++++++++++++-------------- 2 files changed, 83 insertions(+), 56 deletions(-) diff --git a/drivers/gpu/drm/xe/regs/xe_gtt_defs.h b/drivers/gpu/drm/xe/regs/xe_gtt_defs.h index 4d83461e538b..d6bc19ef277b 100644 --- a/drivers/gpu/drm/xe/regs/xe_gtt_defs.h +++ b/drivers/gpu/drm/xe/regs/xe_gtt_defs.h @@ -9,7 +9,11 @@ #define XELPG_GGTT_PTE_PAT0 BIT_ULL(52) #define XELPG_GGTT_PTE_PAT1 BIT_ULL(53) -#define XE_PTE_ADDR_MASK GENMASK_ULL(51, 12) +/* + * Mask for PTE address bits [51:shift]. + * shift is the lower address boundary of page. + */ +#define XE_PAGE_ADDR_MASK(shift) GENMASK_ULL(51, (shift)) #define GGTT_PTE_VFID GENMASK_ULL(11, 2) #define GUC_GGTT_TOP 0xFEE00000 diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c index 15ce77ce7793..46226865269b 100644 --- a/drivers/gpu/drm/xe/xe_pt.c +++ b/drivers/gpu/drm/xe/xe_pt.c @@ -1602,23 +1602,21 @@ static bool xe_pt_check_kill(u64 addr, u64 next, unsigned int level, return false; } -/* page_size = 2^(reclamation_size + XE_PTE_SHIFT) */ -#define COMPUTE_RECLAIM_ADDRESS_MASK(page_size) \ -({ \ - BUILD_BUG_ON(!__builtin_constant_p(page_size)); \ - ilog2(page_size) - XE_PTE_SHIFT; \ -}) - static int generate_reclaim_entry(struct xe_tile *tile, struct xe_page_reclaim_list *prl, u64 pte, struct xe_pt *xe_child) { struct xe_gt *gt = tile->primary_gt; struct xe_guc_page_reclaim_entry *reclaim_entries = prl->entries; - u64 phys_addr = pte & XE_PTE_ADDR_MASK; + bool is_2m = xe_child->level == 1 && (pte & XE_PDE_PS_2M); + bool is_64k = xe_child->level == 0 && ((pte & XE_PTE_PS64) || xe_child->is_compact); + u32 page_shift = is_2m ? ilog2(SZ_2M) : is_64k ? ilog2(SZ_64K) : ilog2(SZ_4K); + /* Physical address bits start at page shift: 2M->[51:21], 64K->[51:16], 4K->[51:12] */ + u64 phys_addr = pte & XE_PAGE_ADDR_MASK(page_shift); + /* Page address is relative to 4K page regardless of entry level */ u64 phys_page = phys_addr >> XE_PTE_SHIFT; int num_entries = prl->num_entries; - u32 reclamation_size; + u32 reclamation_size = page_shift - XE_PTE_SHIFT; xe_tile_assert(tile, xe_child->level <= MAX_HUGEPTE_LEVEL); xe_tile_assert(tile, reclaim_entries); @@ -1633,18 +1631,12 @@ static int generate_reclaim_entry(struct xe_tile *tile, * Page size is computed as 2^(reclamation_size + XE_PTE_SHIFT) bytes. * Only 4K, 64K (level 0), and 2M pages are supported by hardware for page reclaim */ - if (xe_child->level == 0 && !(pte & XE_PTE_PS64)) { - xe_gt_stats_incr(gt, XE_GT_STATS_ID_PRL_4K_ENTRY_COUNT, 1); - reclamation_size = COMPUTE_RECLAIM_ADDRESS_MASK(SZ_4K); /* reclamation_size = 0 */ - xe_tile_assert(tile, phys_addr % SZ_4K == 0); - } else if (xe_child->level == 0) { - xe_gt_stats_incr(gt, XE_GT_STATS_ID_PRL_64K_ENTRY_COUNT, 1); - reclamation_size = COMPUTE_RECLAIM_ADDRESS_MASK(SZ_64K); /* reclamation_size = 4 */ - xe_tile_assert(tile, phys_addr % SZ_64K == 0); - } else if (xe_child->level == 1 && pte & XE_PDE_PS_2M) { + if (is_2m) { xe_gt_stats_incr(gt, XE_GT_STATS_ID_PRL_2M_ENTRY_COUNT, 1); - reclamation_size = COMPUTE_RECLAIM_ADDRESS_MASK(SZ_2M); /* reclamation_size = 9 */ - xe_tile_assert(tile, phys_addr % SZ_2M == 0); + } else if (is_64k) { + xe_gt_stats_incr(gt, XE_GT_STATS_ID_PRL_64K_ENTRY_COUNT, 1); + } else if (xe_child->level == 0) { + xe_gt_stats_incr(gt, XE_GT_STATS_ID_PRL_4K_ENTRY_COUNT, 1); } else { xe_page_reclaim_list_abort(tile->primary_gt, prl, "unsupported PTE level=%u pte=%#llx", @@ -1665,6 +1657,48 @@ static int generate_reclaim_entry(struct xe_tile *tile, return 0; } +static int add_pte_to_prl(struct xe_tile *tile, struct xe_page_reclaim_list *prl, + struct xe_pt *xe_child, u64 pte, u64 addr) +{ + /* + * In rare scenarios, pte may not be written yet due to racy conditions. + * In such cases, invalidate the PRL and fallback to full PPC invalidation. + */ + if (!pte) { + xe_page_reclaim_list_abort(tile->primary_gt, prl, + "found zero pte at addr=%#llx", addr); + return -EINVAL; + } + + /* Ensure it is a defined page */ + xe_tile_assert(tile, xe_child->level == 0 || + (pte & (XE_PDE_PS_2M | XE_PDPE_PS_1G))); + + /* Account for NULL terminated entry on end (-1) */ + if (prl->num_entries >= XE_PAGE_RECLAIM_MAX_ENTRIES - 1) { + xe_page_reclaim_list_abort(tile->primary_gt, prl, + "overflow while adding pte=%#llx", pte); + return -ENOSPC; + } + + return generate_reclaim_entry(tile, prl, pte, xe_child); +} + +static bool add_compact_pt_prl(struct xe_tile *tile, struct xe_page_reclaim_list *prl, + struct xe_device *xe, struct xe_pt *compact_pt, u64 addr) +{ + struct iosys_map *map = &compact_pt->bo->vmap; + + for (pgoff_t i = 0; i < SZ_2M / SZ_64K && xe_page_reclaim_list_valid(prl); i++) { + u64 pte = xe_map_rd(xe, map, i * sizeof(u64), u64); + + if (add_pte_to_prl(tile, prl, compact_pt, pte, addr + i * SZ_64K)) + break; + } + + return xe_page_reclaim_list_valid(prl); +} + static int xe_pt_stage_unbind_entry(struct xe_ptw *parent, pgoff_t offset, unsigned int level, u64 addr, u64 next, struct xe_ptw **child, @@ -1674,21 +1708,22 @@ static int xe_pt_stage_unbind_entry(struct xe_ptw *parent, pgoff_t offset, struct xe_pt *xe_child = container_of(*child, typeof(*xe_child), base); struct xe_pt_stage_unbind_walk *xe_walk = container_of(walk, typeof(*xe_walk), base); - struct xe_device *xe = tile_to_xe(xe_walk->tile); + struct xe_page_reclaim_list *prl = xe_walk->prl; + struct xe_tile *tile = xe_walk->tile; + struct xe_device *xe = tile_to_xe(tile); pgoff_t first = xe_pt_offset(addr, xe_child->level, walk); bool killed; XE_WARN_ON(!*child); XE_WARN_ON(!level); /* Check for leaf node */ - if (xe_walk->prl && xe_page_reclaim_list_valid(xe_walk->prl) && + if (prl && xe_page_reclaim_list_valid(prl) && xe_child->level <= MAX_HUGEPTE_LEVEL) { struct iosys_map *leaf_map = &xe_child->bo->vmap; pgoff_t count = xe_pt_num_entries(addr, next, xe_child->level, walk); for (pgoff_t i = 0; i < count; i++) { u64 pte; - int ret; /* * If not a leaf pt, skip unless non-leaf pt is interleaved between @@ -1698,10 +1733,23 @@ static int xe_pt_stage_unbind_entry(struct xe_ptw *parent, pgoff_t offset, u64 pt_size = 1ULL << walk->shifts[xe_child->level]; bool edge_pt = (i == 0 && !IS_ALIGNED(addr, pt_size)) || (i == count - 1 && !IS_ALIGNED(next, pt_size)); - - if (!edge_pt) { - xe_page_reclaim_list_abort(xe_walk->tile->primary_gt, - xe_walk->prl, + struct xe_pt *child_pt = + container_of(xe_child->base.children[first + i], + struct xe_pt, base); + + /* Compact PTs always fill a full 2M-aligned slot, never an edge. */ + XE_WARN_ON(child_pt->is_compact && edge_pt); + if (edge_pt) + continue; + + /* Walker never descends into compact PTs, descend now */ + if (child_pt->is_compact) { + if (!add_compact_pt_prl(tile, prl, xe, child_pt, + addr + (u64)i * pt_size)) + break; + } else { + xe_page_reclaim_list_abort(tile->primary_gt, + prl, "PT is skipped by walk at level=%u offset=%lu", xe_child->level, first + i); break; @@ -1711,37 +1759,12 @@ static int xe_pt_stage_unbind_entry(struct xe_ptw *parent, pgoff_t offset, pte = xe_map_rd(xe, leaf_map, (first + i) * sizeof(u64), u64); - /* - * In rare scenarios, pte may not be written yet due to racy conditions. - * In such cases, invalidate the PRL and fallback to full PPC invalidation. - */ - if (!pte) { - xe_page_reclaim_list_abort(xe_walk->tile->primary_gt, xe_walk->prl, - "found zero pte at addr=%#llx", addr); + if (add_pte_to_prl(tile, prl, xe_child, pte, addr)) break; - } - - /* Ensure it is a defined page */ - xe_tile_assert(xe_walk->tile, xe_child->level == 0 || - (pte & (XE_PDE_PS_2M | XE_PDPE_PS_1G))); /* An entry should be added for 64KB but contigious 4K have XE_PTE_PS64 */ if (pte & XE_PTE_PS64) i += 15; /* Skip other 15 consecutive 4K pages in the 64K page */ - - /* Account for NULL terminated entry on end (-1) */ - if (xe_walk->prl->num_entries < XE_PAGE_RECLAIM_MAX_ENTRIES - 1) { - ret = generate_reclaim_entry(xe_walk->tile, xe_walk->prl, - pte, xe_child); - if (ret) - break; - } else { - /* overflow, mark as invalid */ - xe_page_reclaim_list_abort(xe_walk->tile->primary_gt, xe_walk->prl, - "overflow while adding pte=%#llx", - pte); - break; - } } } @@ -1751,7 +1774,7 @@ static int xe_pt_stage_unbind_entry(struct xe_ptw *parent, pgoff_t offset, * Verify if any PTE are potentially dropped at non-leaf levels, either from being * killed or the page walk covers the region. */ - if (xe_walk->prl && xe_page_reclaim_list_valid(xe_walk->prl) && + if (prl && xe_page_reclaim_list_valid(prl) && xe_child->level > MAX_HUGEPTE_LEVEL && xe_child->num_live) { bool covered = xe_pt_covers(addr, next, xe_child->level, &xe_walk->base); @@ -1760,7 +1783,7 @@ static int xe_pt_stage_unbind_entry(struct xe_ptw *parent, pgoff_t offset, * we need to invalidate the PRL. */ if (killed || covered) - xe_page_reclaim_list_abort(xe_walk->tile->primary_gt, xe_walk->prl, + xe_page_reclaim_list_abort(tile->primary_gt, prl, "kill at level=%u addr=%#llx next=%#llx num_live=%u", level, addr, next, xe_child->num_live); } -- cgit v1.2.3 From b9297d19d9df5d4b6c994648570c5dcd1cac68ff Mon Sep 17 00:00:00 2001 From: Francois Dugast Date: Tue, 16 Jun 2026 10:17:56 +0200 Subject: drm/xe/pt: Fix NULL pointer dereference in xe_pt_zap_ptes_entry() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The page-table walk framework may pass a NULL *child pointer for unpopulated entries. xe_pt_zap_ptes_entry() called container_of(*child) before checking for NULL, then dereferenced the result, causing a crash. Move the container_of() call after a NULL guard, so the function returns early instead of proceeding with an invalid pointer. XE_WARN_ON is kept to help root cause the issue, but we now bail instead of crashing the driver. v2: Comment that triggering XE_WARN_ON is unexpected behavior (Matt Brost) Fixes: dd08ebf6c352 ("drm/xe: Introduce a new DRM driver for Intel GPUs") Cc: Matthew Brost Cc: Thomas Hellström Reviewed-by: Matthew Brost Link: https://lore.kernel.org/r/20260616081756.286918-1-francois.dugast@intel.com Signed-off-by: Francois Dugast --- drivers/gpu/drm/xe/xe_pt.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c index 46226865269b..0959e0e88a14 100644 --- a/drivers/gpu/drm/xe/xe_pt.c +++ b/drivers/gpu/drm/xe/xe_pt.c @@ -885,12 +885,20 @@ static int xe_pt_zap_ptes_entry(struct xe_ptw *parent, pgoff_t offset, { struct xe_pt_zap_ptes_walk *xe_walk = container_of(walk, typeof(*xe_walk), base); - struct xe_pt *xe_child = container_of(*child, typeof(*xe_child), base); + struct xe_pt *xe_child; pgoff_t end_offset; - XE_WARN_ON(!*child); XE_WARN_ON(!level); + /* + * Below would be unexpected behavior that needs to be root caused + * but better warn and bail than crash the driver. + */ + if (XE_WARN_ON(!*child)) + return 0; + + xe_child = container_of(*child, typeof(*xe_child), base); + /* * Note that we're called from an entry callback, and we're dealing * with the child of that entry rather than the parent, so need to -- cgit v1.2.3 From 173202a5a3a9e6590194ce0f5880d1529a71ade7 Mon Sep 17 00:00:00 2001 From: Lu Yao Date: Wed, 17 Jun 2026 09:25:16 +0800 Subject: drm/xe: Remove redundant exec_queue_suspended() check in submit_exec_queue() There already has a check for exec_queue_suspended(q) that returns early if suspended. Fixes: b7fb55cc3364 ("drm/xe/multi_queue: skip submit when primary queue is suspended") Signed-off-by: Lu Yao Reviewed-by: Rodrigo Vivi Link: https://patch.msgid.link/20260617012516.19930-1-yaolu@kylinos.cn Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_guc_submit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index afe5d99cdd8b..9458bf477fa6 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -1163,7 +1163,7 @@ static void submit_exec_queue(struct xe_exec_queue *q, struct xe_sched_job *job) if (exec_queue_suspended(q)) return; - if (!exec_queue_enabled(q) && !exec_queue_suspended(q)) { + if (!exec_queue_enabled(q)) { action[len++] = XE_GUC_ACTION_SCHED_CONTEXT_MODE_SET; action[len++] = q->guc->id; action[len++] = GUC_CONTEXT_ENABLE; -- cgit v1.2.3 From ea8439751ddc3af189121100631554ebe4bbb2d4 Mon Sep 17 00:00:00 2001 From: Zhan Wei Date: Wed, 3 Jun 2026 00:17:07 +0800 Subject: drm/xe/hwmon: document DG2 fan speed reporting quirk On DG2 the driver always shows two fan channels, because the FSC_READ_NUM_FANS command does not work on some cards. OEMs decide how the fans map to tach channels, so two fans can share one tach line. When that happens, the second channel reads 0 RPM even though the fan is spinning. Note this on the fan2_input ABI entry so the steady 0 RPM is not mistaken for a driver bug. Fixes: 28f79ac609de ("drm/xe/hwmon: expose fan speed") Signed-off-by: Zhan Wei Reviewed-by: Raag Jadav Link: https://patch.msgid.link/20260602161707.18922-1-zhanwei919@gmail.com Signed-off-by: Rodrigo Vivi --- Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon index 55ab45f669ac..0da739d9a816 100644 --- a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon +++ b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon @@ -251,6 +251,13 @@ Description: RO. Fan 2 speed in RPM. Only supported for particular Intel Xe graphics platforms. + On DG2 the driver always shows two fan channels, because the + FSC_READ_NUM_FANS command does not work on some cards. OEMs + decide how the fans map to tach channels, so two fans can share + one tach line. When that happens, the second channel + reads 0 RPM even though the fan is spinning. This is normal, not + a bug. + What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon/fan3_input Date: March 2025 KernelVersion: 6.16 -- cgit v1.2.3 From 4d39b3e7d5937e1672316da79de3b683b5d7257a Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Wed, 17 Jun 2026 12:24:45 -0700 Subject: drm/xe: Reformat xe_rtp_types.h Adjust whitespace / newlines in xe_rtp_types.h to make it easier to read and more consistent with other files. No functional change. Reviewed-by: Gustavo Sousa Link: https://patch.msgid.link/20260617-rtp_with_dynamic_vals-v2-1-3f4cb34c2ea1@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/xe_rtp_types.h | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_rtp_types.h b/drivers/gpu/drm/xe/xe_rtp_types.h index 58018ae4f8cc..1d7c63d0ae94 100644 --- a/drivers/gpu/drm/xe/xe_rtp_types.h +++ b/drivers/gpu/drm/xe/xe_rtp_types.h @@ -22,20 +22,24 @@ struct xe_gt; */ struct xe_rtp_action { /** @reg: Register */ - struct xe_reg reg; + struct xe_reg reg; + /** * @clr_bits: bits to clear when updating register. It's always a * superset of bits being modified */ - u32 clr_bits; + u32 clr_bits; + /** @set_bits: bits to set when updating register */ - u32 set_bits; + u32 set_bits; + #define XE_RTP_NOCHECK .read_mask = 0 /** @read_mask: mask for bits to consider when reading value back */ - u32 read_mask; + u32 read_mask; + #define XE_RTP_ACTION_FLAG_ENGINE_BASE BIT(0) /** @flags: flags to apply on rule evaluation or action */ - u8 flags; + u8 flags; }; enum { @@ -69,6 +73,7 @@ struct xe_rtp_rule { u8 platform; u8 subplatform; }; + /* * MATCH_GRAPHICS_VERSION / XE_RTP_MATCH_GRAPHICS_VERSION_RANGE / * MATCH_MEDIA_VERSION / XE_RTP_MATCH_MEDIA_VERSION_RANGE @@ -78,15 +83,18 @@ struct xe_rtp_rule { #define XE_RTP_END_VERSION_UNDEFINED U32_MAX u32 ver_end; }; + /* MATCH_STEP */ struct { u8 step_start; u8 step_end; }; + /* MATCH_ENGINE_CLASS / MATCH_NOT_ENGINE_CLASS */ struct { u8 engine_class; }; + /* MATCH_FUNC */ bool (*match_func)(const struct xe_device *xe, const struct xe_gt *gt, -- cgit v1.2.3 From 7a8884330059d345537f5bbcb74d806144dafe2b Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Wed, 17 Jun 2026 12:24:46 -0700 Subject: drm/xe/rtp: Add FIELD_SET_FUNC RTP action Most of our RTP programming involves programming constant values into register fields. However there are a few cases (e.g., RING_CMD_CCTL programming) that rely on dynamic per-GT or per-engine checks to decide what value will be programmed. Add a FIELD_SET_FUNC RTP action which will call the provided function pointer once at RTP processing time to determine the appropriate value. v2: - Tweak kerneldoc to avoid duplicating explanation from FIELD_SET. (Gustavo) Reviewed-by: Gustavo Sousa Link: https://patch.msgid.link/20260617-rtp_with_dynamic_vals-v2-2-3f4cb34c2ea1@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/xe_rtp.c | 10 ++++++++-- drivers/gpu/drm/xe/xe_rtp.h | 19 +++++++++++++++++++ drivers/gpu/drm/xe/xe_rtp_types.h | 17 +++++++++++++++-- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_rtp.c b/drivers/gpu/drm/xe/xe_rtp.c index 83a40e1f9528..6a8d6ea68f25 100644 --- a/drivers/gpu/drm/xe/xe_rtp.c +++ b/drivers/gpu/drm/xe/xe_rtp.c @@ -227,17 +227,23 @@ static bool rule_matches(const struct xe_device *xe, static void rtp_add_sr_entry(const struct xe_rtp_action *action, struct xe_gt *gt, + struct xe_hw_engine *hwe, u32 mmio_base, struct xe_reg_sr *sr) { struct xe_reg_sr_entry sr_entry = { .reg = action->reg, .clr_bits = action->clr_bits, - .set_bits = action->set_bits, .read_mask = action->read_mask, }; + if (action->use_func) + sr_entry.set_bits = action->set_func(gt, hwe); + else + sr_entry.set_bits = action->set_bits; + sr_entry.reg.addr += mmio_base; + xe_reg_sr_add(sr, &sr_entry, gt); } @@ -259,7 +265,7 @@ static bool rtp_process_one_sr(const struct xe_rtp_entry_sr *entry, else mmio_base = 0; - rtp_add_sr_entry(action, gt, mmio_base, sr); + rtp_add_sr_entry(action, gt, hwe, mmio_base, sr); } return true; diff --git a/drivers/gpu/drm/xe/xe_rtp.h b/drivers/gpu/drm/xe/xe_rtp.h index 2cc65053cd07..0032f68ea187 100644 --- a/drivers/gpu/drm/xe/xe_rtp.h +++ b/drivers/gpu/drm/xe/xe_rtp.h @@ -322,6 +322,25 @@ struct xe_reg_sr; .clr_bits = (mask_bits_), .set_bits = (val_), \ .read_mask = 0, ##__VA_ARGS__ } +/** + * XE_RTP_ACTION_FIELD_SET_FUNC: Set a bit range to the value returned by a function + * @reg_: Register + * @mask_bits_: Mask of bits to be changed in the register, forming a field + * @func_: Function that returns value to set in the field denoted by @mask_bits_ + * @...: Additional fields to override in the struct xe_rtp_action entry + * + * This macro works like XE_RTP_ACTION_FIELD_SET(), except that the + * field value is evaluated at the time the RTP table is processed. + * + * @func_ will only be called a single time, when the RTP table is being + * processed. After processing, the value in the reg_sr entry is fixed and + * will not be re-evaluated. + */ +#define XE_RTP_ACTION_FIELD_SET_FUNC(reg_, mask_bits_, func_, ...) \ + { .reg = XE_RTP_DROP_CAST(reg_), \ + .clr_bits = mask_bits_, .set_func = func_, .use_func = 1, \ + .read_mask = mask_bits_, ##__VA_ARGS__ } + /** * XE_RTP_ACTION_WHITELIST - Add register to userspace whitelist * @reg_: Register diff --git a/drivers/gpu/drm/xe/xe_rtp_types.h b/drivers/gpu/drm/xe/xe_rtp_types.h index 1d7c63d0ae94..b78092fa06e0 100644 --- a/drivers/gpu/drm/xe/xe_rtp_types.h +++ b/drivers/gpu/drm/xe/xe_rtp_types.h @@ -30,8 +30,14 @@ struct xe_rtp_action { */ u32 clr_bits; - /** @set_bits: bits to set when updating register */ - u32 set_bits; + union { + /** @set_bits: bits to set when updating register */ + u32 set_bits; + + /** @set_func: function to provide bits to set when updating register */ + u32 (*set_func)(struct xe_gt *gt, + struct xe_hw_engine *hwe); + }; #define XE_RTP_NOCHECK .read_mask = 0 /** @read_mask: mask for bits to consider when reading value back */ @@ -40,6 +46,13 @@ struct xe_rtp_action { #define XE_RTP_ACTION_FLAG_ENGINE_BASE BIT(0) /** @flags: flags to apply on rule evaluation or action */ u8 flags; + + /** + * @use_func: + * Internal flag indicating @set_func should be called instead of + * using @set_bits. + */ + u8 use_func:1; }; enum { -- cgit v1.2.3 From 431a233c1710c89c1ff4beab4aa2131065943108 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Wed, 17 Jun 2026 12:24:47 -0700 Subject: drm/xe: Move engines' LRC programming RTP table off the stack The 'lrc_setup' RTP table was allocated on the stack because it wasn't truly constant and needed to calculate the proper value for BLIT_CCTL at runtime based on other stack variables. Using the FIELD_SET_FUNC action allows us to make the table itself truly constant and move it off the stack; the BLIT_CCTL value is now calculated during RTP table processing. v2: - Made table static Reviewed-by: Gustavo Sousa Link: https://patch.msgid.link/20260617-rtp_with_dynamic_vals-v2-3-3f4cb34c2ea1@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/xe_hw_engine.c | 60 ++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c index 98265293f2dc..603bb197801a 100644 --- a/drivers/gpu/drm/xe/xe_hw_engine.c +++ b/drivers/gpu/drm/xe/xe_hw_engine.c @@ -337,39 +337,41 @@ static bool xe_rtp_cfeg_wmtp_disabled(const struct xe_device *xe, return xe_mmio_read32(&hwe->gt->mmio, XEHP_FUSE4) & CFEG_WMTP_DISABLE; } +static u32 blit_cctl_val(struct xe_gt *gt, struct xe_hw_engine *hwe) +{ + return REG_FIELD_PREP(BLIT_CCTL_DST_MOCS_MASK, gt->mocs.uc_index) | + REG_FIELD_PREP(BLIT_CCTL_SRC_MOCS_MASK, gt->mocs.uc_index); +} + +static const struct xe_rtp_table_sr lrc_setup = XE_RTP_TABLE_SR( + /* + * Some blitter commands do not have a field for MOCS, those + * commands will use MOCS index pointed by BLIT_CCTL. + * BLIT_CCTL registers are needed to be programmed to un-cached. + */ + { XE_RTP_NAME("BLIT_CCTL_default_MOCS"), + XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 1274), + ENGINE_CLASS(COPY)), + XE_RTP_ACTIONS(FIELD_SET_FUNC(BLIT_CCTL(0), + BLIT_CCTL_DST_MOCS_MASK | + BLIT_CCTL_SRC_MOCS_MASK, + blit_cctl_val, + XE_RTP_ACTION_FLAG(ENGINE_BASE))) + }, + /* Disable WMTP if HW doesn't support it */ + { XE_RTP_NAME("DISABLE_WMTP_ON_UNSUPPORTED_HW"), + XE_RTP_RULES(FUNC(xe_rtp_cfeg_wmtp_disabled)), + XE_RTP_ACTIONS(FIELD_SET(CS_CHICKEN1(0), + PREEMPT_GPGPU_LEVEL_MASK, + PREEMPT_GPGPU_THREAD_GROUP_LEVEL)), + XE_RTP_ENTRY_FLAG(FOREACH_ENGINE) + }, +); + static void hw_engine_setup_default_lrc_state(struct xe_hw_engine *hwe) { - struct xe_gt *gt = hwe->gt; - const u8 mocs_write_idx = gt->mocs.uc_index; - const u8 mocs_read_idx = gt->mocs.uc_index; - u32 blit_cctl_val = REG_FIELD_PREP(BLIT_CCTL_DST_MOCS_MASK, mocs_write_idx) | - REG_FIELD_PREP(BLIT_CCTL_SRC_MOCS_MASK, mocs_read_idx); struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe); - const struct xe_rtp_table_sr lrc_setup = XE_RTP_TABLE_SR( - /* - * Some blitter commands do not have a field for MOCS, those - * commands will use MOCS index pointed by BLIT_CCTL. - * BLIT_CCTL registers are needed to be programmed to un-cached. - */ - { XE_RTP_NAME("BLIT_CCTL_default_MOCS"), - XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 1274), - ENGINE_CLASS(COPY)), - XE_RTP_ACTIONS(FIELD_SET(BLIT_CCTL(0), - BLIT_CCTL_DST_MOCS_MASK | - BLIT_CCTL_SRC_MOCS_MASK, - blit_cctl_val, - XE_RTP_ACTION_FLAG(ENGINE_BASE))) - }, - /* Disable WMTP if HW doesn't support it */ - { XE_RTP_NAME("DISABLE_WMTP_ON_UNSUPPORTED_HW"), - XE_RTP_RULES(FUNC(xe_rtp_cfeg_wmtp_disabled)), - XE_RTP_ACTIONS(FIELD_SET(CS_CHICKEN1(0), - PREEMPT_GPGPU_LEVEL_MASK, - PREEMPT_GPGPU_THREAD_GROUP_LEVEL)), - XE_RTP_ENTRY_FLAG(FOREACH_ENGINE) - }, - ); xe_rtp_process_to_sr(&ctx, &lrc_setup, &hwe->reg_lrc, true); } -- cgit v1.2.3 From 4ff7902a64c1831dfc70791d2f88125e003d21c2 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Wed, 17 Jun 2026 12:24:48 -0700 Subject: drm/xe: Move engines' non-LRC programming RTP table off the stack The 'engine_sr' RTP table was allocated on the stack because it wasn't truly constant and needed to calculate the proper value for RING_CMD_CCTL at runtime based on other stack variables. Using the FIELD_SET_FUNC action allows us to make the table itself truly constant and move it off the stack; the RING_CMD_CCTL value is now calculated during RTP table processing. v2: - Made table static Reviewed-by: Gustavo Sousa Link: https://patch.msgid.link/20260617-rtp_with_dynamic_vals-v2-4-3f4cb34c2ea1@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/xe_hw_engine.c | 156 ++++++++++++++++++++------------------ 1 file changed, 81 insertions(+), 75 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c index 603bb197801a..7e7411bfe1dc 100644 --- a/drivers/gpu/drm/xe/xe_hw_engine.c +++ b/drivers/gpu/drm/xe/xe_hw_engine.c @@ -387,86 +387,92 @@ void xe_hw_engine_setup_reg_lrc(struct xe_hw_engine *hwe) xe_tuning_process_lrc(hwe); } -static void -hw_engine_setup_default_state(struct xe_hw_engine *hwe) +/* + * RING_CMD_CCTL specifies the default MOCS entry that will be + * used by the command streamer when executing commands that + * don't have a way to explicitly specify a MOCS setting. + * The default should usually reference whichever MOCS entry + * corresponds to uncached behavior, although use of a WB cached + * entry is recommended by the spec in certain circumstances on + * specific platforms. + * Bspec: 72161 + */ +static u32 ring_cmd_cctl_val(struct xe_gt *gt, struct xe_hw_engine *hwe) { - struct xe_gt *gt = hwe->gt; struct xe_device *xe = gt_to_xe(gt); + u8 mocs_read_idx = gt->mocs.uc_index; + + if (hwe->class == XE_ENGINE_CLASS_COMPUTE && IS_DGFX(xe) && + (GRAPHICS_VER(xe) >= 20 || xe->info.platform == XE_PVC)) + mocs_read_idx = gt->mocs.wb_index; + + return REG_FIELD_PREP(CMD_CCTL_WRITE_OVERRIDE_MASK, gt->mocs.uc_index) | + REG_FIELD_PREP(CMD_CCTL_READ_OVERRIDE_MASK, mocs_read_idx); +} + +static const struct xe_rtp_table_sr engine_sr = XE_RTP_TABLE_SR( + { XE_RTP_NAME("RING_CMD_CCTL_default_MOCS"), + XE_RTP_RULES(FUNC(xe_rtp_match_always)), + XE_RTP_ACTIONS(FIELD_SET_FUNC(RING_CMD_CCTL(0), + CMD_CCTL_WRITE_OVERRIDE_MASK | + CMD_CCTL_READ_OVERRIDE_MASK, + ring_cmd_cctl_val, + XE_RTP_ACTION_FLAG(ENGINE_BASE))) + }, + { XE_RTP_NAME("Disable HW status page updates for interrupts"), + XE_RTP_RULES(FUNC(xe_rtp_match_always)), + XE_RTP_ACTIONS(SET(RING_HWSTAM(0), ~0x0, + XE_RTP_ACTION_FLAG(ENGINE_BASE))) + }, + { XE_RTP_NAME("Disable engine 'legacy' mode"), + XE_RTP_RULES(FUNC(xe_rtp_match_always)), + XE_RTP_ACTIONS(SET(GFX_MODE(0), GFX_DISABLE_LEGACY_MODE, + XE_RTP_ACTION_FLAG(ENGINE_BASE))) + }, /* - * RING_CMD_CCTL specifies the default MOCS entry that will be - * used by the command streamer when executing commands that - * don't have a way to explicitly specify a MOCS setting. - * The default should usually reference whichever MOCS entry - * corresponds to uncached behavior, although use of a WB cached - * entry is recommended by the spec in certain circumstances on - * specific platforms. - * Bspec: 72161 + * To allow the GSC engine to go idle on MTL we need to enable + * idle messaging and set the hysteresis value (we use 0xA=5us + * as recommended in spec). On platforms after MTL this is + * enabled by default. */ - const u8 mocs_write_idx = gt->mocs.uc_index; - const u8 mocs_read_idx = hwe->class == XE_ENGINE_CLASS_COMPUTE && IS_DGFX(xe) && - (GRAPHICS_VER(xe) >= 20 || xe->info.platform == XE_PVC) ? - gt->mocs.wb_index : gt->mocs.uc_index; - u32 ring_cmd_cctl_val = REG_FIELD_PREP(CMD_CCTL_WRITE_OVERRIDE_MASK, mocs_write_idx) | - REG_FIELD_PREP(CMD_CCTL_READ_OVERRIDE_MASK, mocs_read_idx); + { XE_RTP_NAME("MTL GSCCS IDLE MSG enable"), + XE_RTP_RULES(MEDIA_VERSION(1300), ENGINE_CLASS(OTHER)), + XE_RTP_ACTIONS(CLR(RING_PSMI_CTL(0), + IDLE_MSG_DISABLE, + XE_RTP_ACTION_FLAG(ENGINE_BASE)), + FIELD_SET(RING_PWRCTX_MAXCNT(0), + IDLE_WAIT_TIME, + 0xA, + XE_RTP_ACTION_FLAG(ENGINE_BASE))) + }, + /* Enable Priority Mem Read */ + { XE_RTP_NAME("Priority_Mem_Read"), + XE_RTP_RULES(GRAPHICS_VERSION_RANGE(2001, XE_RTP_END_VERSION_UNDEFINED)), + XE_RTP_ACTIONS(SET(CSFE_CHICKEN1(0), CS_PRIORITY_MEM_READ, + XE_RTP_ACTION_FLAG(ENGINE_BASE))) + }, + { XE_RTP_NAME("Enable CCS Engine(s)"), + XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1255, XE_RTP_END_VERSION_UNDEFINED), + FUNC(xe_rtp_match_first_render_or_compute)), + XE_RTP_ACTIONS(SET(RCU_MODE, RCU_MODE_CCS_ENABLE)) + }, + /* Use Fixed slice CCS mode */ + { XE_RTP_NAME("RCU_MODE_FIXED_SLICE_CCS_MODE"), + XE_RTP_RULES(FUNC(xe_hw_engine_match_fixed_cslice_mode)), + XE_RTP_ACTIONS(FIELD_SET(RCU_MODE, RCU_MODE_FIXED_SLICE_CCS_MODE, + RCU_MODE_FIXED_SLICE_CCS_MODE)) + }, + { XE_RTP_NAME("Enable MSI-X interrupt support"), + XE_RTP_RULES(FUNC(xe_rtp_match_has_msix)), + XE_RTP_ACTIONS(SET(GFX_MODE(0), GFX_MSIX_INTERRUPT_ENABLE, + XE_RTP_ACTION_FLAG(ENGINE_BASE))) + }, +); + +static void +hw_engine_setup_default_state(struct xe_hw_engine *hwe) +{ struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe); - const struct xe_rtp_table_sr engine_sr = XE_RTP_TABLE_SR( - { XE_RTP_NAME("RING_CMD_CCTL_default_MOCS"), - XE_RTP_RULES(FUNC(xe_rtp_match_always)), - XE_RTP_ACTIONS(FIELD_SET(RING_CMD_CCTL(0), - CMD_CCTL_WRITE_OVERRIDE_MASK | - CMD_CCTL_READ_OVERRIDE_MASK, - ring_cmd_cctl_val, - XE_RTP_ACTION_FLAG(ENGINE_BASE))) - }, - { XE_RTP_NAME("Disable HW status page updates for interrupts"), - XE_RTP_RULES(FUNC(xe_rtp_match_always)), - XE_RTP_ACTIONS(SET(RING_HWSTAM(0), ~0x0, - XE_RTP_ACTION_FLAG(ENGINE_BASE))) - }, - { XE_RTP_NAME("Disable engine 'legacy' mode"), - XE_RTP_RULES(FUNC(xe_rtp_match_always)), - XE_RTP_ACTIONS(SET(GFX_MODE(0), GFX_DISABLE_LEGACY_MODE, - XE_RTP_ACTION_FLAG(ENGINE_BASE))) - }, - /* - * To allow the GSC engine to go idle on MTL we need to enable - * idle messaging and set the hysteresis value (we use 0xA=5us - * as recommended in spec). On platforms after MTL this is - * enabled by default. - */ - { XE_RTP_NAME("MTL GSCCS IDLE MSG enable"), - XE_RTP_RULES(MEDIA_VERSION(1300), ENGINE_CLASS(OTHER)), - XE_RTP_ACTIONS(CLR(RING_PSMI_CTL(0), - IDLE_MSG_DISABLE, - XE_RTP_ACTION_FLAG(ENGINE_BASE)), - FIELD_SET(RING_PWRCTX_MAXCNT(0), - IDLE_WAIT_TIME, - 0xA, - XE_RTP_ACTION_FLAG(ENGINE_BASE))) - }, - /* Enable Priority Mem Read */ - { XE_RTP_NAME("Priority_Mem_Read"), - XE_RTP_RULES(GRAPHICS_VERSION_RANGE(2001, XE_RTP_END_VERSION_UNDEFINED)), - XE_RTP_ACTIONS(SET(CSFE_CHICKEN1(0), CS_PRIORITY_MEM_READ, - XE_RTP_ACTION_FLAG(ENGINE_BASE))) - }, - { XE_RTP_NAME("Enable CCS Engine(s)"), - XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1255, XE_RTP_END_VERSION_UNDEFINED), - FUNC(xe_rtp_match_first_render_or_compute)), - XE_RTP_ACTIONS(SET(RCU_MODE, RCU_MODE_CCS_ENABLE)) - }, - /* Use Fixed slice CCS mode */ - { XE_RTP_NAME("RCU_MODE_FIXED_SLICE_CCS_MODE"), - XE_RTP_RULES(FUNC(xe_hw_engine_match_fixed_cslice_mode)), - XE_RTP_ACTIONS(FIELD_SET(RCU_MODE, RCU_MODE_FIXED_SLICE_CCS_MODE, - RCU_MODE_FIXED_SLICE_CCS_MODE)) - }, - { XE_RTP_NAME("Enable MSI-X interrupt support"), - XE_RTP_RULES(FUNC(xe_rtp_match_has_msix)), - XE_RTP_ACTIONS(SET(GFX_MODE(0), GFX_MSIX_INTERRUPT_ENABLE, - XE_RTP_ACTION_FLAG(ENGINE_BASE))) - }, - ); xe_rtp_process_to_sr(&ctx, &engine_sr, &hwe->reg_sr, false); } -- cgit v1.2.3 From c47ffed42b016ddeea2a45fa9631edb2bd4e88ed Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Wed, 17 Jun 2026 12:24:49 -0700 Subject: drm/xe/rtp: Add kunit tests to exercise FIELD_SET_FUNC action Add a couple additional tests to the RTP kunit suite that ensure FIELD_SET_FUNC() actions are evaluated properly and the values properly consolidate/conflict with values coming from other literal SET/FIELD_SET rules. Suggested-by: Gustavo Sousa Reviewed-by: Gustavo Sousa Link: https://patch.msgid.link/20260617-rtp_with_dynamic_vals-v2-5-3f4cb34c2ea1@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/tests/xe_rtp_test.c | 52 ++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/drivers/gpu/drm/xe/tests/xe_rtp_test.c b/drivers/gpu/drm/xe/tests/xe_rtp_test.c index 3d0688d058d9..367811621880 100644 --- a/drivers/gpu/drm/xe/tests/xe_rtp_test.c +++ b/drivers/gpu/drm/xe/tests/xe_rtp_test.c @@ -280,6 +280,11 @@ static void xe_rtp_rules_tests(struct kunit *test) KUNIT_EXPECT_EQ(test, err, param->expected_err); } +static u32 bits_2_3_set(struct xe_gt *gt, struct xe_hw_engine *hwe) +{ + return REG_BIT(2) | REG_BIT(3); +} + static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { { .name = "coalesce-same-reg", @@ -300,6 +305,29 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { }, ), }, + { + .name = "coalesce-same-reg-literal-and-func", + .expected_reg = REGULAR_REG1, + .expected_set_bits = REG_BIT(0) | REG_BIT(1) | REG_BIT(2) | REG_BIT(3), + .expected_clr_bits = REG_BIT(0) | REG_BIT(1) | REG_BIT(2) | REG_BIT(3), + .expected_active = BIT(0) | BIT(1), + .expected_count_sr_entries = 1, + /* Different bits on the same register: create a single entry */ + .table = XE_RTP_TABLE_SR( + { XE_RTP_NAME("basic-1"), + XE_RTP_RULES(FUNC(match_yes)), + XE_RTP_ACTIONS(FIELD_SET(REGULAR_REG1, + REG_BIT(0) | REG_BIT(1), + REG_BIT(0) | REG_BIT(1))) + }, + { XE_RTP_NAME("basic-2"), + XE_RTP_RULES(FUNC(match_yes)), + XE_RTP_ACTIONS(FIELD_SET_FUNC(REGULAR_REG1, + REG_BIT(2) | REG_BIT(3), + bits_2_3_set)) + }, + ), + }, { .name = "no-match-no-add", .expected_reg = REGULAR_REG1, @@ -417,6 +445,30 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { }, ), }, + { + .name = "conflict-not-disjoint-literal-and-func", + .expected_reg = REGULAR_REG1, + .expected_set_bits = REG_BIT(1) | REG_BIT(2), + .expected_clr_bits = REG_BIT(1) | REG_BIT(2), + .expected_active = BIT(0) | BIT(1), + .expected_count_sr_entries = 1, + .expected_sr_errors = 1, + .table = XE_RTP_TABLE_SR( + { XE_RTP_NAME("basic-1"), + XE_RTP_RULES(FUNC(match_yes)), + XE_RTP_ACTIONS(FIELD_SET(REGULAR_REG1, + REG_BIT(1) | REG_BIT(2), + REG_BIT(1) | REG_BIT(2))) + }, + /* drop: bits are not disjoint with previous entries */ + { XE_RTP_NAME("basic-2"), + XE_RTP_RULES(FUNC(match_yes)), + XE_RTP_ACTIONS(FIELD_SET_FUNC(REGULAR_REG1, + REG_BIT(2) | REG_BIT(3), + bits_2_3_set)) + }, + ), + }, { .name = "conflict-reg-type", .expected_reg = REGULAR_REG1, -- cgit v1.2.3 From ff33a7f1d4ea8094ac2b44654737752de6f05a77 Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Thu, 18 Jun 2026 21:01:26 +0530 Subject: drm/xe/hw_error: Defeature hardware error handling with system controller Hardware errors are reported through System Controller on the platforms that support it, and never routed as direct IRQ to SGUnit. Defeature their handling to prevent unexpected side effects. Signed-off-by: Raag Jadav Reviewed-by: Riana Tauro Link: https://patch.msgid.link/20260618153209.110899-2-raag.jadav@intel.com Signed-off-by: Riana Tauro --- drivers/gpu/drm/xe/xe_hw_error.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_hw_error.c b/drivers/gpu/drm/xe/xe_hw_error.c index 4b72959b2276..db228043dbe5 100644 --- a/drivers/gpu/drm/xe/xe_hw_error.c +++ b/drivers/gpu/drm/xe/xe_hw_error.c @@ -437,6 +437,16 @@ static void hw_error_source_handler(struct xe_tile *tile, const enum hardware_er if (!IS_DGFX(xe)) return; + /* + * Hardware errors are reported through System Controller on the platforms that + * support it, and never routed as direct IRQ to SGUnit. So we should never be + * here for those platforms. + */ + if (xe->info.has_sysctrl) { + drm_err_ratelimited(&xe->drm, HW_ERR "Invalid error routing\n"); + return; + } + spin_lock_irqsave(&xe->irq.lock, flags); err_src = xe_mmio_read32(&tile->mmio, DEV_ERR_STAT_REG(hw_err)); if (!err_src) { -- cgit v1.2.3 From c1a3f611952e80c2fe9ded854bf2c5d56aee697e Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 8 Jun 2026 20:28:29 +0200 Subject: drm/xe/mcr: Prefer GT-oriented WARN messages In all functions where xe_gt pointer is relevant, we should use GT-oriented diagnostic messages using macros from xe_gt_printk.h Signed-off-by: Michal Wajdeczko Reviewed-by: Rodrigo Vivi Link: https://patch.msgid.link/20260608182829.913-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_gt_mcr.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_gt_mcr.c b/drivers/gpu/drm/xe/xe_gt_mcr.c index 04f0098070a4..d11cc9e25cdb 100644 --- a/drivers/gpu/drm/xe/xe_gt_mcr.c +++ b/drivers/gpu/drm/xe/xe_gt_mcr.c @@ -507,7 +507,7 @@ void xe_gt_mcr_init_early(struct xe_gt *gt) spin_lock_init(>->mcr_lock); if (gt->info.type == XE_GT_TYPE_MEDIA) { - drm_WARN_ON(&xe->drm, MEDIA_VER(xe) < 13); + xe_gt_WARN_ON(gt, MEDIA_VER(xe) < 13); if (MEDIA_VER(xe) >= 30) { gt->steering[OADDRM].ranges = xe2lpm_gpmxmt_steering_table; @@ -662,9 +662,9 @@ bool xe_gt_mcr_get_nonterminated_steering(struct xe_gt *gt, for (int type = 0; type < IMPLICIT_STEERING; type++) { if (reg_in_steering_type_ranges(gt, reg, type)) { - drm_WARN(>_to_xe(gt)->drm, !gt->steering[type].initialized, - "Uninitialized usage of MCR register %s/%#x\n", - xe_steering_types[type].name, reg.addr); + xe_gt_WARN(gt, !gt->steering[type].initialized, + "Uninitialized usage of MCR register %s/%#x\n", + xe_steering_types[type].name, reg.addr); *group = gt->steering[type].group_target; *instance = gt->steering[type].instance_target; @@ -679,9 +679,9 @@ bool xe_gt_mcr_get_nonterminated_steering(struct xe_gt *gt, * Not found in a steering table and not a register with implicit * steering. Just steer to 0/0 as a guess and raise a warning. */ - drm_WARN(>_to_xe(gt)->drm, true, - "Did not find MCR register %#x in any MCR steering table\n", - reg.addr); + xe_gt_WARN(gt, true, + "Did not find MCR register %#x in any MCR steering table\n", + reg.addr); *group = 0; *instance = 0; @@ -710,7 +710,7 @@ static void mcr_lock(struct xe_gt *gt) __acquires(>->mcr_lock) ret = xe_mmio_wait32(>->mmio, STEER_SEMAPHORE, 0x1, 0x1, 10, NULL, true); - drm_WARN_ON_ONCE(&xe->drm, ret == -ETIMEDOUT); + xe_gt_WARN_ON_ONCE(gt, ret == -ETIMEDOUT); } static void mcr_unlock(struct xe_gt *gt) __releases(>->mcr_lock) -- cgit v1.2.3 From cdeb5e248de11537cf23cd5174f6c55bab2e850b Mon Sep 17 00:00:00 2001 From: Riana Tauro Date: Thu, 18 Jun 2026 11:36:35 +0530 Subject: drm/xe/uapi: Add additional error components to xe drm_ras Add additional Error components supported by XE drm_ras (Reliability, Availability and Serviceability). Reviewed-by: Aravind Iddamsetty Reviewed-by: Mallesh Koujalagi Acked-by: Rodrigo Vivi Link: https://patch.msgid.link/20260618060633.2790109-9-riana.tauro@intel.com Signed-off-by: Riana Tauro --- include/uapi/drm/xe_drm.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h index 48e9f1fdb78d..50c80af4ad4e 100644 --- a/include/uapi/drm/xe_drm.h +++ b/include/uapi/drm/xe_drm.h @@ -2589,6 +2589,12 @@ enum drm_xe_ras_error_component { DRM_XE_RAS_ERR_COMP_CORE_COMPUTE = 1, /** @DRM_XE_RAS_ERR_COMP_SOC_INTERNAL: SoC Internal Error */ DRM_XE_RAS_ERR_COMP_SOC_INTERNAL, + /** @DRM_XE_RAS_ERR_COMP_DEVICE_MEMORY: Device Memory Error */ + DRM_XE_RAS_ERR_COMP_DEVICE_MEMORY, + /** @DRM_XE_RAS_ERR_COMP_PCIE: PCIe Subsystem Error */ + DRM_XE_RAS_ERR_COMP_PCIE, + /** @DRM_XE_RAS_ERR_COMP_FABRIC: Fabric Subsystem Error */ + DRM_XE_RAS_ERR_COMP_FABRIC, /** @DRM_XE_RAS_ERR_COMP_MAX: Max Error */ DRM_XE_RAS_ERR_COMP_MAX /* non-ABI */ }; @@ -2606,7 +2612,10 @@ enum drm_xe_ras_error_component { */ #define DRM_XE_RAS_ERROR_COMPONENT_NAMES { \ [DRM_XE_RAS_ERR_COMP_CORE_COMPUTE] = "core-compute", \ - [DRM_XE_RAS_ERR_COMP_SOC_INTERNAL] = "soc-internal" \ + [DRM_XE_RAS_ERR_COMP_SOC_INTERNAL] = "soc-internal", \ + [DRM_XE_RAS_ERR_COMP_DEVICE_MEMORY] = "device-memory", \ + [DRM_XE_RAS_ERR_COMP_PCIE] = "pcie", \ + [DRM_XE_RAS_ERR_COMP_FABRIC] = "fabric", \ } #if defined(__cplusplus) -- cgit v1.2.3 From fe48a86980798ffc78c8713ec964877c8594610d Mon Sep 17 00:00:00 2001 From: Riana Tauro Date: Thu, 18 Jun 2026 11:36:36 +0530 Subject: drm/xe/xe_ras: Add support to get error counter value Add request/response structures and helper functions to query system controller to get error counter value. Reviewed-by: Raag Jadav Link: https://patch.msgid.link/20260618060633.2790109-10-riana.tauro@intel.com Signed-off-by: Riana Tauro --- drivers/gpu/drm/xe/xe_ras.c | 91 +++++++++++++++++++++++++++ drivers/gpu/drm/xe/xe_ras.h | 3 + drivers/gpu/drm/xe/xe_ras_types.h | 26 ++++++++ drivers/gpu/drm/xe/xe_sysctrl_mailbox.c | 28 +++++++++ drivers/gpu/drm/xe/xe_sysctrl_mailbox.h | 3 + drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h | 2 + 6 files changed, 153 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_ras.c b/drivers/gpu/drm/xe/xe_ras.c index 4cb16b419b0c..96702234d7ec 100644 --- a/drivers/gpu/drm/xe/xe_ras.c +++ b/drivers/gpu/drm/xe/xe_ras.c @@ -4,11 +4,14 @@ */ #include "xe_device.h" +#include "xe_pm.h" #include "xe_printk.h" #include "xe_ras.h" #include "xe_ras_types.h" #include "xe_sysctrl.h" #include "xe_sysctrl_event_types.h" +#include "xe_sysctrl_mailbox.h" +#include "xe_sysctrl_mailbox_types.h" /* Severity of detected errors */ enum xe_ras_severity { @@ -50,6 +53,36 @@ static const char *const xe_ras_components[] = { }; static_assert(ARRAY_SIZE(xe_ras_components) == XE_RAS_COMP_MAX); +static u8 drm_to_xe_ras_severity(u8 severity) +{ + switch (severity) { + case DRM_XE_RAS_ERR_SEV_CORRECTABLE: + return XE_RAS_SEV_CORRECTABLE; + case DRM_XE_RAS_ERR_SEV_UNCORRECTABLE: + return XE_RAS_SEV_UNCORRECTABLE; + default: + return XE_RAS_SEV_NOT_SUPPORTED; + } +} + +static u8 drm_to_xe_ras_component(u8 component) +{ + switch (component) { + case DRM_XE_RAS_ERR_COMP_CORE_COMPUTE: + return XE_RAS_COMP_CORE_COMPUTE; + case DRM_XE_RAS_ERR_COMP_SOC_INTERNAL: + return XE_RAS_COMP_SOC_INTERNAL; + case DRM_XE_RAS_ERR_COMP_DEVICE_MEMORY: + return XE_RAS_COMP_DEVICE_MEMORY; + case DRM_XE_RAS_ERR_COMP_PCIE: + return XE_RAS_COMP_PCIE; + case DRM_XE_RAS_ERR_COMP_FABRIC: + return XE_RAS_COMP_FABRIC; + default: + return XE_RAS_COMP_NOT_SUPPORTED; + } +} + static inline const char *sev_to_str(u8 severity) { if (severity >= XE_RAS_SEV_MAX) @@ -91,3 +124,61 @@ void xe_ras_counter_threshold_crossed(struct xe_device *xe, comp_to_str(component), sev_to_str(severity)); } } + +static int get_counter(struct xe_device *xe, struct xe_ras_error_class *counter, u32 *value) +{ + struct xe_ras_get_counter_response response = {0}; + struct xe_ras_get_counter_request request = {0}; + struct xe_sysctrl_mailbox_command command = {0}; + struct xe_ras_error_common *common; + size_t rlen; + int ret; + + request.counter = *counter; + + xe_sysctrl_create_command(&command, XE_SYSCTRL_GROUP_GFSP, XE_SYSCTRL_CMD_GET_COUNTER, + &request, sizeof(request), &response, sizeof(response)); + + ret = xe_sysctrl_send_command(&xe->sc, &command, &rlen); + if (ret) { + xe_err(xe, "sysctrl: failed to get counter %d\n", ret); + return ret; + } + + if (rlen != sizeof(response)) { + xe_err(xe, "sysctrl: unexpected get counter response length %zu (expected %zu)\n", + rlen, sizeof(response)); + return -EIO; + } + + common = &response.counter.common; + *value = response.value; + + xe_dbg(xe, "[RAS]: get counter %u for %s %s\n", *value, comp_to_str(common->component), + sev_to_str(common->severity)); + + return 0; +} + +/** + * xe_ras_get_counter() - Get error counter value + * @xe: Xe device instance + * @severity: Error severity to be queried (&enum drm_xe_ras_error_severity) + * @component: Error component to be queried (&enum drm_xe_ras_error_component) + * @value: Counter value + * + * This function retrieves the value of a specific error counter based on + * the error severity and component. + * + * Return: 0 on success, negative error code on failure. + */ +int xe_ras_get_counter(struct xe_device *xe, u8 severity, u8 component, u32 *value) +{ + struct xe_ras_error_class counter = {0}; + + counter.common.severity = drm_to_xe_ras_severity(severity); + counter.common.component = drm_to_xe_ras_component(component); + + guard(xe_pm_runtime)(xe); + return get_counter(xe, &counter, value); +} diff --git a/drivers/gpu/drm/xe/xe_ras.h b/drivers/gpu/drm/xe/xe_ras.h index ea90593b62dc..e148debd5d41 100644 --- a/drivers/gpu/drm/xe/xe_ras.h +++ b/drivers/gpu/drm/xe/xe_ras.h @@ -6,10 +6,13 @@ #ifndef _XE_RAS_H_ #define _XE_RAS_H_ +#include + struct xe_device; struct xe_sysctrl_event_response; void xe_ras_counter_threshold_crossed(struct xe_device *xe, struct xe_sysctrl_event_response *response); +int xe_ras_get_counter(struct xe_device *xe, u8 severity, u8 component, u32 *value); #endif diff --git a/drivers/gpu/drm/xe/xe_ras_types.h b/drivers/gpu/drm/xe/xe_ras_types.h index 4e63c67f806a..fdfebaeb5ed2 100644 --- a/drivers/gpu/drm/xe/xe_ras_types.h +++ b/drivers/gpu/drm/xe/xe_ras_types.h @@ -70,4 +70,30 @@ struct xe_ras_threshold_crossed { struct xe_ras_error_class counters[XE_RAS_NUM_COUNTERS]; } __packed; +/** + * struct xe_ras_get_counter_request - Request structure for get counter + */ +struct xe_ras_get_counter_request { + /** @counter: Error counter to be queried */ + struct xe_ras_error_class counter; + /** @reserved: Reserved for future use */ + u32 reserved; +} __packed; + +/** + * struct xe_ras_get_counter_response - Response structure for get counter + */ +struct xe_ras_get_counter_response { + /** @counter: Error counter that was queried */ + struct xe_ras_error_class counter; + /** @value: Current counter value */ + u32 value; + /** @timestamp: Timestamp when counter was last updated */ + u64 timestamp; + /** @threshold: Threshold value for the counter */ + u32 threshold; + /** @reserved: Reserved */ + u32 reserved[57]; +} __packed; + #endif diff --git a/drivers/gpu/drm/xe/xe_sysctrl_mailbox.c b/drivers/gpu/drm/xe/xe_sysctrl_mailbox.c index 3caa9f15875f..e13eebaac1d0 100644 --- a/drivers/gpu/drm/xe/xe_sysctrl_mailbox.c +++ b/drivers/gpu/drm/xe/xe_sysctrl_mailbox.c @@ -293,6 +293,34 @@ static int sysctrl_send_command(struct xe_sysctrl *sc, return 0; } +/** + * xe_sysctrl_create_command() - Create system controller command + * @command: Sysctrl command structure + * @group_id: Command group ID + * @cmd_id: Command ID + * @request: Pointer to request buffer (can be NULL) + * @request_len: Size of request buffer + * @response: Pointer to response buffer + * @response_len: Size of response buffer + * + * Helper function to create sysctrl command to be sent via %xe_sysctrl_send_command() + */ +void xe_sysctrl_create_command(struct xe_sysctrl_mailbox_command *command, u8 group_id, u8 cmd_id, + void *request, size_t request_len, void *response, + size_t response_len) +{ + struct xe_sysctrl_app_msg_hdr header = {0}; + + header.data = FIELD_PREP(APP_HDR_GROUP_ID_MASK, group_id) | + FIELD_PREP(APP_HDR_COMMAND_MASK, cmd_id); + + command->header = header; + command->data_in = request; + command->data_in_len = request_len; + command->data_out = response; + command->data_out_len = response_len; +} + /** * xe_sysctrl_mailbox_init - Initialize System Controller mailbox interface * @sc: System controller structure diff --git a/drivers/gpu/drm/xe/xe_sysctrl_mailbox.h b/drivers/gpu/drm/xe/xe_sysctrl_mailbox.h index f67e9234de48..fb434cc165b2 100644 --- a/drivers/gpu/drm/xe/xe_sysctrl_mailbox.h +++ b/drivers/gpu/drm/xe/xe_sysctrl_mailbox.h @@ -23,6 +23,9 @@ struct xe_sysctrl_mailbox_command; #define XE_SYSCTRL_APP_HDR_VERSION(hdr) \ FIELD_GET(APP_HDR_VERSION_MASK, (hdr)->data) +void xe_sysctrl_create_command(struct xe_sysctrl_mailbox_command *command, u8 group_id, u8 cmd_id, + void *request, size_t request_len, void *response, + size_t response_len); void xe_sysctrl_mailbox_init(struct xe_sysctrl *sc); int xe_sysctrl_send_command(struct xe_sysctrl *sc, struct xe_sysctrl_mailbox_command *cmd, diff --git a/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h b/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h index 84d7c647e743..b315847cbf64 100644 --- a/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h +++ b/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h @@ -22,9 +22,11 @@ enum xe_sysctrl_group { /** * enum xe_sysctrl_gfsp_cmd - Commands supported by GFSP group * + * @XE_SYSCTRL_CMD_GET_COUNTER: Get error counter value * @XE_SYSCTRL_CMD_GET_PENDING_EVENT: Retrieve pending event */ enum xe_sysctrl_gfsp_cmd { + XE_SYSCTRL_CMD_GET_COUNTER = 0x03, XE_SYSCTRL_CMD_GET_PENDING_EVENT = 0x07, }; -- cgit v1.2.3 From 2801adbd3449d449431a09dd9382a8ee4f928a2f Mon Sep 17 00:00:00 2001 From: Riana Tauro Date: Thu, 18 Jun 2026 11:36:37 +0530 Subject: drm/xe/xe_ras: Add support to clear error counter value Add structures and helper function to clear error counter value. Reviewed-by: Raag Jadav Link: https://patch.msgid.link/20260618060633.2790109-11-riana.tauro@intel.com Signed-off-by: Riana Tauro --- drivers/gpu/drm/xe/xe_ras.c | 86 +++++++++++++++++++++++++++ drivers/gpu/drm/xe/xe_ras.h | 1 + drivers/gpu/drm/xe/xe_ras_types.h | 25 ++++++++ drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h | 2 + 4 files changed, 114 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_ras.c b/drivers/gpu/drm/xe/xe_ras.c index 96702234d7ec..a11ea841f9f1 100644 --- a/drivers/gpu/drm/xe/xe_ras.c +++ b/drivers/gpu/drm/xe/xe_ras.c @@ -34,6 +34,17 @@ enum xe_ras_component { XE_RAS_COMP_MAX }; +/* RAS response status codes */ +enum xe_ras_response_status { + XE_RAS_STATUS_SUCCESS = 0, + XE_RAS_STATUS_INVALID_PARAM, + XE_RAS_STATUS_OP_NOT_SUPPORTED, + XE_RAS_STATUS_TIMEOUT, + XE_RAS_STATUS_HARDWARE_FAILURE, + XE_RAS_STATUS_INSUFFICIENT_RESOURCES, + XE_RAS_STATUS_MAX +}; + static const char *const xe_ras_severities[] = { [XE_RAS_SEV_NOT_SUPPORTED] = "Not Supported", [XE_RAS_SEV_CORRECTABLE] = "Correctable Error", @@ -83,6 +94,26 @@ static u8 drm_to_xe_ras_component(u8 component) } } +static int ras_status_to_errno(u32 status) +{ + switch (status) { + case XE_RAS_STATUS_SUCCESS: + return 0; + case XE_RAS_STATUS_INVALID_PARAM: + return -EINVAL; + case XE_RAS_STATUS_OP_NOT_SUPPORTED: + return -EOPNOTSUPP; + case XE_RAS_STATUS_TIMEOUT: + return -ETIMEDOUT; + case XE_RAS_STATUS_HARDWARE_FAILURE: + return -EIO; + case XE_RAS_STATUS_INSUFFICIENT_RESOURCES: + return -ENOSPC; + default: + return -EPROTO; + } +} + static inline const char *sev_to_str(u8 severity) { if (severity >= XE_RAS_SEV_MAX) @@ -182,3 +213,58 @@ int xe_ras_get_counter(struct xe_device *xe, u8 severity, u8 component, u32 *val guard(xe_pm_runtime)(xe); return get_counter(xe, &counter, value); } + +/** + * xe_ras_clear_counter() - Clear error counter value + * @xe: Xe device instance + * @severity: Error severity to be cleared (&enum drm_xe_ras_error_severity) + * @component: Error component to be cleared (&enum drm_xe_ras_error_component) + * + * This function clears the value of a specific error counter based on + * the error severity and component. + * + * Return: 0 on success, negative error code on failure. + */ +int xe_ras_clear_counter(struct xe_device *xe, u8 severity, u8 component) +{ + struct xe_ras_clear_counter_response response = {0}; + struct xe_ras_clear_counter_request request = {0}; + struct xe_sysctrl_mailbox_command command = {0}; + struct xe_ras_error_class *counter; + size_t rlen; + int ret; + + counter = &request.counter; + counter->common.severity = drm_to_xe_ras_severity(severity); + counter->common.component = drm_to_xe_ras_component(component); + + xe_sysctrl_create_command(&command, XE_SYSCTRL_GROUP_GFSP, XE_SYSCTRL_CMD_CLEAR_COUNTER, + &request, sizeof(request), &response, sizeof(response)); + + guard(xe_pm_runtime)(xe); + ret = xe_sysctrl_send_command(&xe->sc, &command, &rlen); + if (ret) { + xe_err(xe, "sysctrl: failed to clear counter %d\n", ret); + return ret; + } + + if (rlen != sizeof(response)) { + xe_err(xe, "sysctrl: unexpected clear counter response length %zu (expected %zu)\n", + rlen, sizeof(response)); + return -EIO; + } + + ret = ras_status_to_errno(response.status); + if (ret) { + xe_err(xe, "sysctrl: clear counter command failed with status %#x\n", + response.status); + return ret; + } + + counter = &response.counter; + + xe_dbg(xe, "[RAS]: clear counter for %s %s\n", comp_to_str(counter->common.component), + sev_to_str(counter->common.severity)); + + return 0; +} diff --git a/drivers/gpu/drm/xe/xe_ras.h b/drivers/gpu/drm/xe/xe_ras.h index e148debd5d41..a2089fc3c3ff 100644 --- a/drivers/gpu/drm/xe/xe_ras.h +++ b/drivers/gpu/drm/xe/xe_ras.h @@ -14,5 +14,6 @@ struct xe_sysctrl_event_response; void xe_ras_counter_threshold_crossed(struct xe_device *xe, struct xe_sysctrl_event_response *response); int xe_ras_get_counter(struct xe_device *xe, u8 severity, u8 component, u32 *value); +int xe_ras_clear_counter(struct xe_device *xe, u8 severity, u8 component); #endif diff --git a/drivers/gpu/drm/xe/xe_ras_types.h b/drivers/gpu/drm/xe/xe_ras_types.h index fdfebaeb5ed2..6688e11f57a8 100644 --- a/drivers/gpu/drm/xe/xe_ras_types.h +++ b/drivers/gpu/drm/xe/xe_ras_types.h @@ -96,4 +96,29 @@ struct xe_ras_get_counter_response { u32 reserved[57]; } __packed; +/** + * struct xe_ras_clear_counter_request - Request structure for clear counter + */ +struct xe_ras_clear_counter_request { + /** @counter: Counter class to be cleared */ + struct xe_ras_error_class counter; + /** @reserved: Reserved for future use */ + u32 reserved; +} __packed; + +/** + * struct xe_ras_clear_counter_response - Response structure for clear counter + */ +struct xe_ras_clear_counter_response { + /** @counter: Counter class that was cleared */ + struct xe_ras_error_class counter; + /** @reserved: Reserved */ + u32 reserved; + /** @timestamp: Timestamp when the counter was cleared */ + u64 timestamp; + /** @status: Status of the clear operation */ + u32 status; + /** @reserved1: Reserved for future use */ + u32 reserved1[3]; +} __packed; #endif diff --git a/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h b/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h index b315847cbf64..6e3753554510 100644 --- a/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h +++ b/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h @@ -23,10 +23,12 @@ enum xe_sysctrl_group { * enum xe_sysctrl_gfsp_cmd - Commands supported by GFSP group * * @XE_SYSCTRL_CMD_GET_COUNTER: Get error counter value + * @XE_SYSCTRL_CMD_CLEAR_COUNTER: Clear error counter value * @XE_SYSCTRL_CMD_GET_PENDING_EVENT: Retrieve pending event */ enum xe_sysctrl_gfsp_cmd { XE_SYSCTRL_CMD_GET_COUNTER = 0x03, + XE_SYSCTRL_CMD_CLEAR_COUNTER = 0x04, XE_SYSCTRL_CMD_GET_PENDING_EVENT = 0x07, }; -- cgit v1.2.3 From 2f02918ab20397aa5c6b03f46db6bd7024a0ce6a Mon Sep 17 00:00:00 2001 From: Riana Tauro Date: Thu, 18 Jun 2026 11:36:38 +0530 Subject: drm/xe/xe_drm_ras: Wire get and clear counter callbacks Hook CRI get-error-counter and clear-error-counter support to xe_drm_ras to allow userspace to query and clear counters if supported. Integrate this with xe_drm_ras. Usage: Query all error counter value using ynl $ sudo ynl --family drm_ras --dump get-error-counter --json \ '{"node-id":0}' [{'error-id': 1, 'error-name': 'core-compute', 'error-value': 0}, {'error-id': 2, 'error-name': 'soc-internal', 'error-value': 0}, {'error-id': 3, 'error-name': 'device-memory', 'error-value': 0}, {'error-id': 4, 'error-name': 'pcie', 'error-value': 0}, {'error-id': 5, 'error-name': 'fabric', 'error-value': 0}] Query single error counter value using ynl $ sudo ynl --family drm_ras --do get-error-counter --json \ '{"node-id":1, "error-id":1}' {'error-id': 1, 'error-name': 'core-compute', 'error-value': 2} Clear counter using ynl $ sudo ynl --family drm_ras --do clear-error-counter --json '\ {"node-id":1, "error-id":1}' None Reviewed-by: Raag Jadav Link: https://patch.msgid.link/20260618060633.2790109-12-riana.tauro@intel.com Signed-off-by: Riana Tauro --- drivers/gpu/drm/xe/xe_drm_ras.c | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_drm_ras.c b/drivers/gpu/drm/xe/xe_drm_ras.c index cd236f53699e..7937d8ba0ed9 100644 --- a/drivers/gpu/drm/xe/xe_drm_ras.c +++ b/drivers/gpu/drm/xe/xe_drm_ras.c @@ -11,27 +11,46 @@ #include "xe_device_types.h" #include "xe_drm_ras.h" +#include "xe_ras.h" static const char * const error_components[] = DRM_XE_RAS_ERROR_COMPONENT_NAMES; static const char * const error_severity[] = DRM_XE_RAS_ERROR_SEVERITY_NAMES; -static int hw_query_error_counter(struct xe_drm_ras_counter *info, - u32 error_id, const char **name, u32 *val) +static int query_error_counter(struct xe_device *xe, + enum drm_xe_ras_error_severity severity, + u32 error_id, const char **name, u32 *val) { + struct xe_drm_ras *ras = &xe->ras; + struct xe_drm_ras_counter *info = ras->info[severity]; + if (!info || !info[error_id].name) return -ENOENT; *name = info[error_id].name; + + /* Fetch counter from system controller if supported */ + if (xe->info.has_sysctrl) + return xe_ras_get_counter(xe, severity, error_id, val); + *val = atomic_read(&info[error_id].counter); return 0; } -static int hw_clear_error_counter(struct xe_drm_ras_counter *info, u32 error_id) +static int clear_error_counter(struct xe_device *xe, + enum drm_xe_ras_error_severity severity, + u32 error_id) { + struct xe_drm_ras *ras = &xe->ras; + struct xe_drm_ras_counter *info = ras->info[severity]; + if (!info || !info[error_id].name) return -ENOENT; + /* Clear counter from system controller if supported */ + if (xe->info.has_sysctrl) + return xe_ras_clear_counter(xe, severity, error_id); + atomic_set(&info[error_id].counter, 0); return 0; @@ -41,38 +60,30 @@ static int query_uncorrectable_error_counter(struct drm_ras_node *ep, u32 error_ const char **name, u32 *val) { struct xe_device *xe = ep->priv; - struct xe_drm_ras *ras = &xe->ras; - struct xe_drm_ras_counter *info = ras->info[DRM_XE_RAS_ERR_SEV_UNCORRECTABLE]; - return hw_query_error_counter(info, error_id, name, val); + return query_error_counter(xe, DRM_XE_RAS_ERR_SEV_UNCORRECTABLE, error_id, name, val); } static int clear_uncorrectable_error_counter(struct drm_ras_node *node, u32 error_id) { struct xe_device *xe = node->priv; - struct xe_drm_ras *ras = &xe->ras; - struct xe_drm_ras_counter *info = ras->info[DRM_XE_RAS_ERR_SEV_UNCORRECTABLE]; - return hw_clear_error_counter(info, error_id); + return clear_error_counter(xe, DRM_XE_RAS_ERR_SEV_UNCORRECTABLE, error_id); } static int query_correctable_error_counter(struct drm_ras_node *ep, u32 error_id, const char **name, u32 *val) { struct xe_device *xe = ep->priv; - struct xe_drm_ras *ras = &xe->ras; - struct xe_drm_ras_counter *info = ras->info[DRM_XE_RAS_ERR_SEV_CORRECTABLE]; - return hw_query_error_counter(info, error_id, name, val); + return query_error_counter(xe, DRM_XE_RAS_ERR_SEV_CORRECTABLE, error_id, name, val); } static int clear_correctable_error_counter(struct drm_ras_node *node, u32 error_id) { struct xe_device *xe = node->priv; - struct xe_drm_ras *ras = &xe->ras; - struct xe_drm_ras_counter *info = ras->info[DRM_XE_RAS_ERR_SEV_CORRECTABLE]; - return hw_clear_error_counter(info, error_id); + return clear_error_counter(xe, DRM_XE_RAS_ERR_SEV_CORRECTABLE, error_id); } static struct xe_drm_ras_counter *allocate_and_copy_counters(struct xe_device *xe) -- cgit v1.2.3 From 8a1f196b37bf14c7f8c6793d235e66adeef6c2c5 Mon Sep 17 00:00:00 2001 From: Riana Tauro Date: Thu, 18 Jun 2026 11:36:39 +0530 Subject: drm/xe: Move xe drm_ras initialization Move xe drm_ras registration to RAS initialization flow and keep hardware error initialization for processing errors reported via irq. Move soc remapper and system controller initialization up in xe_device_probe as RAS initialization depends on both. Cc: Anoop Vijay Cc: Umesh Nerlige Ramappa Reviewed-by: Raag Jadav Link: https://patch.msgid.link/20260618060633.2790109-13-riana.tauro@intel.com Signed-off-by: Riana Tauro --- drivers/gpu/drm/xe/xe_device.c | 19 +++++++++++-------- drivers/gpu/drm/xe/xe_hw_error.c | 13 ------------- drivers/gpu/drm/xe/xe_ras.c | 15 +++++++++++++++ drivers/gpu/drm/xe/xe_ras.h | 1 + 4 files changed, 27 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index ef730f2bdf32..b687a2eeead3 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -61,6 +61,7 @@ #include "xe_psmi.h" #include "xe_pxp.h" #include "xe_query.h" +#include "xe_ras.h" #include "xe_shrinker.h" #include "xe_soc_remapper.h" #include "xe_survivability_mode.h" @@ -998,6 +999,16 @@ int xe_device_probe(struct xe_device *xe) if (err) return err; + err = xe_soc_remapper_init(xe); + if (err) + return err; + + err = xe_sysctrl_init(xe); + if (err) + return err; + + xe_ras_init(xe); + /* * Now that GT is initialized (TTM in particular), * we can try to init display, and inherit the initial fb. @@ -1038,10 +1049,6 @@ int xe_device_probe(struct xe_device *xe) xe_nvm_init(xe); - err = xe_soc_remapper_init(xe); - if (err) - return err; - err = xe_heci_gsc_init(xe); if (err) return err; @@ -1080,10 +1087,6 @@ int xe_device_probe(struct xe_device *xe) if (err) goto err_unregister_display; - err = xe_sysctrl_init(xe); - if (err) - goto err_unregister_display; - err = xe_device_sysfs_init(xe); if (err) goto err_unregister_display; diff --git a/drivers/gpu/drm/xe/xe_hw_error.c b/drivers/gpu/drm/xe/xe_hw_error.c index db228043dbe5..4a4b363fc844 100644 --- a/drivers/gpu/drm/xe/xe_hw_error.c +++ b/drivers/gpu/drm/xe/xe_hw_error.c @@ -526,14 +526,6 @@ void xe_hw_error_irq_handler(struct xe_tile *tile, const u32 master_ctl) } } -static int hw_error_info_init(struct xe_device *xe) -{ - if (xe->info.platform != XE_PVC) - return 0; - - return xe_drm_ras_init(xe); -} - /* * Process hardware errors during boot */ @@ -560,16 +552,11 @@ static void process_hw_errors(struct xe_device *xe) void xe_hw_error_init(struct xe_device *xe) { struct xe_tile *tile = xe_device_get_root_tile(xe); - int ret; if (!IS_DGFX(xe) || IS_SRIOV_VF(xe)) return; INIT_WORK(&tile->csc_hw_error_work, csc_hw_error_work); - ret = hw_error_info_init(xe); - if (ret) - drm_err(&xe->drm, "Failed to initialize XE DRM RAS (%pe)\n", ERR_PTR(ret)); - process_hw_errors(xe); } diff --git a/drivers/gpu/drm/xe/xe_ras.c b/drivers/gpu/drm/xe/xe_ras.c index a11ea841f9f1..71ee9eeb1896 100644 --- a/drivers/gpu/drm/xe/xe_ras.c +++ b/drivers/gpu/drm/xe/xe_ras.c @@ -4,6 +4,7 @@ */ #include "xe_device.h" +#include "xe_drm_ras.h" #include "xe_pm.h" #include "xe_printk.h" #include "xe_ras.h" @@ -268,3 +269,17 @@ int xe_ras_clear_counter(struct xe_device *xe, u8 severity, u8 component) return 0; } + +/** + * xe_ras_init - Initialize Xe RAS + * @xe: xe device instance + * + * Register drm_ras nodes + */ +void xe_ras_init(struct xe_device *xe) +{ + if (xe->info.platform != XE_PVC) + return; + + xe_drm_ras_init(xe); +} diff --git a/drivers/gpu/drm/xe/xe_ras.h b/drivers/gpu/drm/xe/xe_ras.h index a2089fc3c3ff..ba0b0224df23 100644 --- a/drivers/gpu/drm/xe/xe_ras.h +++ b/drivers/gpu/drm/xe/xe_ras.h @@ -15,5 +15,6 @@ void xe_ras_counter_threshold_crossed(struct xe_device *xe, struct xe_sysctrl_event_response *response); int xe_ras_get_counter(struct xe_device *xe, u8 severity, u8 component, u32 *value); int xe_ras_clear_counter(struct xe_device *xe, u8 severity, u8 component); +void xe_ras_init(struct xe_device *xe); #endif -- cgit v1.2.3 From 63dfab5786ca925f6bc90903b7a7b77c99f4708f Mon Sep 17 00:00:00 2001 From: Riana Tauro Date: Thu, 18 Jun 2026 11:36:40 +0530 Subject: drm/xe/xe_ras: Add drm_ras feature flag Add xe drm_ras feature flag. Enable this flag for PVC and CRI to support exposing RAS error counters via netlink. Reviewed-by: Raag Jadav Link: https://patch.msgid.link/20260618060633.2790109-14-riana.tauro@intel.com Signed-off-by: Riana Tauro --- drivers/gpu/drm/xe/xe_device.c | 1 + drivers/gpu/drm/xe/xe_device_types.h | 2 ++ drivers/gpu/drm/xe/xe_pci.c | 3 +++ drivers/gpu/drm/xe/xe_pci_types.h | 1 + drivers/gpu/drm/xe/xe_ras.c | 2 +- 5 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index b687a2eeead3..d3fbcf10f8ab 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -742,6 +742,7 @@ static void vf_update_device_info(struct xe_device *xe) xe->info.has_late_bind = 0; xe->info.skip_guc_pc = 1; xe->info.skip_pcode = 1; + xe->info.has_drm_ras = false; } static int xe_device_vram_alloc(struct xe_device *xe) diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index 32dd2ffbc796..4e2f115f14e2 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -156,6 +156,8 @@ struct xe_device { u8 has_cached_pt:1; /** @info.has_device_atomics_on_smem: Supports device atomics on SMEM */ u8 has_device_atomics_on_smem:1; + /** @info.has_drm_ras: Device supports drm_ras (Reliability, Availability, Serviceability) */ + u8 has_drm_ras:1; /** @info.has_fan_control: Device supports fan control */ u8 has_fan_control:1; /** @info.has_flat_ccs: Whether flat CCS metadata is used */ diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index 3165686e3e04..c9d4fb6c4ff6 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -355,6 +355,7 @@ static const __maybe_unused struct xe_device_desc pvc_desc = { PLATFORM(PVC), .dma_mask_size = 52, .has_display = false, + .has_drm_ras = true, .has_gsc_nvm = 1, .has_heci_gscfi = 1, .max_gt_per_tile = 1, @@ -457,6 +458,7 @@ static const struct xe_device_desc cri_desc = { PLATFORM(CRESCENTISLAND), .dma_mask_size = 52, .has_display = false, + .has_drm_ras = true, .has_flat_ccs = false, .has_gsc_nvm = 1, .has_i2c = true, @@ -760,6 +762,7 @@ static int xe_info_init_early(struct xe_device *xe, xe->info.is_dgfx = desc->is_dgfx; xe->info.has_cached_pt = desc->has_cached_pt; + xe->info.has_drm_ras = desc->has_drm_ras; xe->info.has_fan_control = desc->has_fan_control; /* runtime fusing may force flat_ccs to disabled later */ xe->info.has_flat_ccs = desc->has_flat_ccs; diff --git a/drivers/gpu/drm/xe/xe_pci_types.h b/drivers/gpu/drm/xe/xe_pci_types.h index 5b85e2c24b7b..24d4a3d00517 100644 --- a/drivers/gpu/drm/xe/xe_pci_types.h +++ b/drivers/gpu/drm/xe/xe_pci_types.h @@ -40,6 +40,7 @@ struct xe_device_desc { u8 has_cached_pt:1; u8 has_display:1; + u8 has_drm_ras:1; u8 has_fan_control:1; u8 has_flat_ccs:1; u8 has_gsc_nvm:1; diff --git a/drivers/gpu/drm/xe/xe_ras.c b/drivers/gpu/drm/xe/xe_ras.c index 71ee9eeb1896..44f4e1a3455b 100644 --- a/drivers/gpu/drm/xe/xe_ras.c +++ b/drivers/gpu/drm/xe/xe_ras.c @@ -278,7 +278,7 @@ int xe_ras_clear_counter(struct xe_device *xe, u8 severity, u8 component) */ void xe_ras_init(struct xe_device *xe) { - if (xe->info.platform != XE_PVC) + if (!xe->info.has_drm_ras) return; xe_drm_ras_init(xe); -- cgit v1.2.3 From 90511bdcfda97211c01f1d945d4ea616578d8fca Mon Sep 17 00:00:00 2001 From: Ashutosh Dixit Date: Mon, 15 Jun 2026 15:42:19 -0700 Subject: drm/xe/rtp: Add RING_FORCE_TO_NONPRIV_DENY to OA whitelists Unconditionally whitelisting OA registers is a security violation. Set RING_FORCE_TO_NONPRIV_DENY bit in OA nonpriv slots, so that OA registers don't get whitelisted by default after probe, gt reset, resume and engine reset. Fixes: 828a8eaf37c3 ("drm/xe/oa: Add MMIO trigger support") Cc: stable@vger.kernel.org # v6.12+ Suggested-by: Umesh Nerlige Ramappa Signed-off-by: Ashutosh Dixit Reviewed-by: Umesh Nerlige Ramappa Link: https://patch.msgid.link/20260615224227.34880-2-ashutosh.dixit@intel.com --- drivers/gpu/drm/xe/xe_reg_whitelist.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.c b/drivers/gpu/drm/xe/xe_reg_whitelist.c index 2e84b1c49f37..2d8ddb57412c 100644 --- a/drivers/gpu/drm/xe/xe_reg_whitelist.c +++ b/drivers/gpu/drm/xe/xe_reg_whitelist.c @@ -104,10 +104,12 @@ static const struct xe_rtp_table_sr register_whitelist = XE_RTP_TABLE_SR( RING_FORCE_TO_NONPRIV_ACCESS_RW)) }, +#define WHITELIST_DENY(r, f) WHITELIST(r, (f) | RING_FORCE_TO_NONPRIV_DENY) + #define WHITELIST_OA_MMIO_TRG(trg, status, head) \ - WHITELIST(trg, RING_FORCE_TO_NONPRIV_ACCESS_RW), \ - WHITELIST(status, RING_FORCE_TO_NONPRIV_ACCESS_RD), \ - WHITELIST(head, RING_FORCE_TO_NONPRIV_ACCESS_RD | RING_FORCE_TO_NONPRIV_RANGE_4) + WHITELIST_DENY(trg, RING_FORCE_TO_NONPRIV_ACCESS_RW), \ + WHITELIST_DENY(status, RING_FORCE_TO_NONPRIV_ACCESS_RD), \ + WHITELIST_DENY(head, RING_FORCE_TO_NONPRIV_ACCESS_RD | RING_FORCE_TO_NONPRIV_RANGE_4) #define WHITELIST_OAG_MMIO_TRG \ WHITELIST_OA_MMIO_TRG(OAG_MMIOTRIGGER, OAG_OASTATUS, OAG_OAHEADPTR) -- cgit v1.2.3 From c478244a9e2d14b3f1f92e8bd293919e554622a5 Mon Sep 17 00:00:00 2001 From: Ashutosh Dixit Date: Mon, 15 Jun 2026 15:42:20 -0700 Subject: drm/xe/rtp: Maintain OA whitelists separately OA registers are dynamically whitelisted (and again dewhitelisted) on OA stream open/close. Maintaining OA whitelists separately from non-OA register whitlists simplifies this management of OA register whitelisting/dewhitelisting. Fixes: 828a8eaf37c3 ("drm/xe/oa: Add MMIO trigger support") Cc: stable@vger.kernel.org # v6.12+ Signed-off-by: Ashutosh Dixit Reviewed-by: Umesh Nerlige Ramappa Link: https://patch.msgid.link/20260615224227.34880-3-ashutosh.dixit@intel.com --- drivers/gpu/drm/xe/xe_gt_debugfs.c | 4 +++- drivers/gpu/drm/xe/xe_hw_engine.c | 2 ++ drivers/gpu/drm/xe/xe_hw_engine_types.h | 8 ++++++++ drivers/gpu/drm/xe/xe_reg_whitelist.c | 5 +++++ 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_gt_debugfs.c b/drivers/gpu/drm/xe/xe_gt_debugfs.c index f45306308cd6..c38bcacb27e4 100644 --- a/drivers/gpu/drm/xe/xe_gt_debugfs.c +++ b/drivers/gpu/drm/xe/xe_gt_debugfs.c @@ -149,8 +149,10 @@ static int register_save_restore(struct xe_gt *gt, struct drm_printer *p) drm_printf(p, "\n"); drm_printf(p, "Whitelist\n"); - for_each_hw_engine(hwe, gt, id) + for_each_hw_engine(hwe, gt, id) { xe_reg_whitelist_dump(&hwe->reg_whitelist, p); + xe_reg_whitelist_dump(&hwe->oa_whitelist, p); + } return 0; } diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c index 7e7411bfe1dc..76aee461bcbe 100644 --- a/drivers/gpu/drm/xe/xe_hw_engine.c +++ b/drivers/gpu/drm/xe/xe_hw_engine.c @@ -580,6 +580,8 @@ static void hw_engine_init_early(struct xe_gt *gt, struct xe_hw_engine *hwe, hw_engine_setup_default_state(hwe); xe_reg_sr_init(&hwe->reg_whitelist, hwe->name, gt_to_xe(gt)); + xe_reg_sr_init(&hwe->oa_whitelist, hwe->name, gt_to_xe(gt)); + xe_reg_sr_init(&hwe->oa_sr, hwe->name, gt_to_xe(gt)); xe_reg_whitelist_process_engine(hwe); } diff --git a/drivers/gpu/drm/xe/xe_hw_engine_types.h b/drivers/gpu/drm/xe/xe_hw_engine_types.h index 2cf898e682f5..84c097da9b6f 100644 --- a/drivers/gpu/drm/xe/xe_hw_engine_types.h +++ b/drivers/gpu/drm/xe/xe_hw_engine_types.h @@ -130,6 +130,14 @@ struct xe_hw_engine { * @reg_whitelist: table with registers to be whitelisted */ struct xe_reg_sr reg_whitelist; + /** + * @oa_whitelist: oa registers to be whitelisted + */ + struct xe_reg_sr oa_whitelist; + /** + * @oa_sr: oa nonpriv whitelist registers, changed on oa stream open/close + */ + struct xe_reg_sr oa_sr; /** * @reg_lrc: LRC workaround registers */ diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.c b/drivers/gpu/drm/xe/xe_reg_whitelist.c index 2d8ddb57412c..6d642c2f6fd7 100644 --- a/drivers/gpu/drm/xe/xe_reg_whitelist.c +++ b/drivers/gpu/drm/xe/xe_reg_whitelist.c @@ -103,6 +103,9 @@ static const struct xe_rtp_table_sr register_whitelist = XE_RTP_TABLE_SR( WHITELIST(VFLSKPD, RING_FORCE_TO_NONPRIV_ACCESS_RW)) }, +); + +static const struct xe_rtp_table_sr oa_whitelist = XE_RTP_TABLE_SR( #define WHITELIST_DENY(r, f) WHITELIST(r, (f) | RING_FORCE_TO_NONPRIV_DENY) @@ -206,6 +209,8 @@ void xe_reg_whitelist_process_engine(struct xe_hw_engine *hwe) xe_rtp_process_to_sr(&ctx, ®ister_whitelist, &hwe->reg_whitelist, false); whitelist_apply_to_hwe(hwe); + + xe_rtp_process_to_sr(&ctx, &oa_whitelist, &hwe->oa_whitelist, false); } /** -- cgit v1.2.3 From 15739920b71ef3c56868973b4e7e3164a793d09d Mon Sep 17 00:00:00 2001 From: Ashutosh Dixit Date: Mon, 15 Jun 2026 15:42:21 -0700 Subject: drm/xe/rtp: Keep track of non-OA nonpriv slots In order to dynamically whitelist/dewhitelist OA registers on OA stream open/close, we need to keep track of nonpriv slots occupied by non-OA register whitelists. Fixes: 828a8eaf37c3 ("drm/xe/oa: Add MMIO trigger support") Cc: stable@vger.kernel.org # v6.12+ Signed-off-by: Ashutosh Dixit Reviewed-by: Umesh Nerlige Ramappa Link: https://patch.msgid.link/20260615224227.34880-4-ashutosh.dixit@intel.com --- drivers/gpu/drm/xe/xe_reg_whitelist.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.c b/drivers/gpu/drm/xe/xe_reg_whitelist.c index 6d642c2f6fd7..b5ae7d26e5ba 100644 --- a/drivers/gpu/drm/xe/xe_reg_whitelist.c +++ b/drivers/gpu/drm/xe/xe_reg_whitelist.c @@ -161,7 +161,7 @@ static const struct xe_rtp_table_sr oa_whitelist = XE_RTP_TABLE_SR( }, ); -static void whitelist_apply_to_hwe(struct xe_hw_engine *hwe) +static int whitelist_apply_to_hwe(struct xe_hw_engine *hwe) { struct xe_reg_sr *sr = &hwe->reg_whitelist; struct xe_reg_sr_entry *entry; @@ -193,6 +193,8 @@ static void whitelist_apply_to_hwe(struct xe_hw_engine *hwe) slot++; } + + return slot; } /** @@ -206,9 +208,10 @@ static void whitelist_apply_to_hwe(struct xe_hw_engine *hwe) void xe_reg_whitelist_process_engine(struct xe_hw_engine *hwe) { struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe); + int first_oa_slot; xe_rtp_process_to_sr(&ctx, ®ister_whitelist, &hwe->reg_whitelist, false); - whitelist_apply_to_hwe(hwe); + first_oa_slot = whitelist_apply_to_hwe(hwe); xe_rtp_process_to_sr(&ctx, &oa_whitelist, &hwe->oa_whitelist, false); } -- cgit v1.2.3 From c3ff77d7235ccef7a0883c2fd981f70ef3aafd21 Mon Sep 17 00:00:00 2001 From: Ashutosh Dixit Date: Mon, 15 Jun 2026 15:42:22 -0700 Subject: drm/xe/rtp: Generalize whitelist_apply_to_hwe Generalize whitelist_apply_to_hwe to construct both non-OA and OA whitelist nonpriv registers. Fixes: 828a8eaf37c3 ("drm/xe/oa: Add MMIO trigger support") Cc: stable@vger.kernel.org # v6.12+ Signed-off-by: Ashutosh Dixit Reviewed-by: Umesh Nerlige Ramappa Link: https://patch.msgid.link/20260615224227.34880-5-ashutosh.dixit@intel.com --- drivers/gpu/drm/xe/xe_reg_whitelist.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.c b/drivers/gpu/drm/xe/xe_reg_whitelist.c index b5ae7d26e5ba..e9d0a0b82527 100644 --- a/drivers/gpu/drm/xe/xe_reg_whitelist.c +++ b/drivers/gpu/drm/xe/xe_reg_whitelist.c @@ -161,9 +161,10 @@ static const struct xe_rtp_table_sr oa_whitelist = XE_RTP_TABLE_SR( }, ); -static int whitelist_apply_to_hwe(struct xe_hw_engine *hwe) +static int whitelist_apply_to_hwe(struct xe_hw_engine *hwe, struct xe_reg_sr *in, + struct xe_reg_sr *out, int first_slot) { - struct xe_reg_sr *sr = &hwe->reg_whitelist; + struct xe_reg_sr *sr = in; struct xe_reg_sr_entry *entry; struct drm_printer p; unsigned long reg; @@ -172,7 +173,7 @@ static int whitelist_apply_to_hwe(struct xe_hw_engine *hwe) xe_gt_dbg(hwe->gt, "Add %s whitelist to engine\n", sr->name); p = xe_gt_dbg_printer(hwe->gt); - slot = 0; + slot = first_slot; xa_for_each(&sr->xa, reg, entry) { struct xe_reg_sr_entry hwe_entry = { .reg = RING_FORCE_TO_NONPRIV(hwe->mmio_base, slot), @@ -189,7 +190,7 @@ static int whitelist_apply_to_hwe(struct xe_hw_engine *hwe) } xe_reg_whitelist_print_entry(&p, 0, reg, entry); - xe_reg_sr_add(&hwe->reg_sr, &hwe_entry, hwe->gt); + xe_reg_sr_add(out, &hwe_entry, hwe->gt); slot++; } @@ -211,7 +212,7 @@ void xe_reg_whitelist_process_engine(struct xe_hw_engine *hwe) int first_oa_slot; xe_rtp_process_to_sr(&ctx, ®ister_whitelist, &hwe->reg_whitelist, false); - first_oa_slot = whitelist_apply_to_hwe(hwe); + first_oa_slot = whitelist_apply_to_hwe(hwe, &hwe->reg_whitelist, &hwe->reg_sr, 0); xe_rtp_process_to_sr(&ctx, &oa_whitelist, &hwe->oa_whitelist, false); } -- cgit v1.2.3 From 3a3c3e56db2923daaf1a5353cd6463a4cdaf4ffa Mon Sep 17 00:00:00 2001 From: Ashutosh Dixit Date: Mon, 15 Jun 2026 15:42:23 -0700 Subject: drm/xe/rtp: Save OA nonpriv registers to register save/restore lists Now we can save OA whitelisting nonpriv registers to register save/restore lists. OA nonpriv registers are saved to both hwe->oa_sr as well as hwe->reg_sr. During probe, resume and gt-reset flows KMD will apply hwe->reg_sr, ensuring OA registers are de-whitelisted after these events. For engine-reset, hwe->reg_sr is registered with GuC and GuC will apply these registers, ensuring OA registers are de-whitelisted after engine resets. hwe->oa_sr is used for whitelisting or de-whitelisting OA registers during OA operation, by toggling the 'deny' bit on oa stream open/close. Fixes: 828a8eaf37c3 ("drm/xe/oa: Add MMIO trigger support") Cc: stable@vger.kernel.org # v6.12+ Signed-off-by: Ashutosh Dixit Reviewed-by: Umesh Nerlige Ramappa Link: https://patch.msgid.link/20260615224227.34880-6-ashutosh.dixit@intel.com --- drivers/gpu/drm/xe/xe_reg_whitelist.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.c b/drivers/gpu/drm/xe/xe_reg_whitelist.c index e9d0a0b82527..76ac23644a4d 100644 --- a/drivers/gpu/drm/xe/xe_reg_whitelist.c +++ b/drivers/gpu/drm/xe/xe_reg_whitelist.c @@ -215,6 +215,18 @@ void xe_reg_whitelist_process_engine(struct xe_hw_engine *hwe) first_oa_slot = whitelist_apply_to_hwe(hwe, &hwe->reg_whitelist, &hwe->reg_sr, 0); xe_rtp_process_to_sr(&ctx, &oa_whitelist, &hwe->oa_whitelist, false); + + /* + * Save oa nonpriv registers to hwe->oa_sr, from which oa registers are whitelisted + * or de-whitelisted, by toggling the 'deny' bit on oa stream open/close + */ + whitelist_apply_to_hwe(hwe, &hwe->oa_whitelist, &hwe->oa_sr, first_oa_slot); + + /* + * Also save oa nonpriv registers to hwe->reg_sr, to ensure oa registers are not + * whitelisted by default after probe, gt reset, resume and engine reset + */ + whitelist_apply_to_hwe(hwe, &hwe->oa_whitelist, &hwe->reg_sr, first_oa_slot); } /** -- cgit v1.2.3 From aeaa7d2bb017272ab9e18759fe00bf758cd3299f Mon Sep 17 00:00:00 2001 From: Ashutosh Dixit Date: Mon, 15 Jun 2026 15:42:24 -0700 Subject: drm/xe/rtp: Toggle 'deny' bit to (de-)whitelist OA regs Whitelist or de-whitelist OA registers by setting or resetting the 'deny' bit in OA nonpriv registers and writing new register values to HW. Fixes: 828a8eaf37c3 ("drm/xe/oa: Add MMIO trigger support") Cc: stable@vger.kernel.org # v6.12+ Signed-off-by: Ashutosh Dixit Reviewed-by: Umesh Nerlige Ramappa Link: https://patch.msgid.link/20260615224227.34880-7-ashutosh.dixit@intel.com --- drivers/gpu/drm/xe/xe_reg_whitelist.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.c b/drivers/gpu/drm/xe/xe_reg_whitelist.c index 76ac23644a4d..7186998df498 100644 --- a/drivers/gpu/drm/xe/xe_reg_whitelist.c +++ b/drivers/gpu/drm/xe/xe_reg_whitelist.c @@ -229,6 +229,21 @@ void xe_reg_whitelist_process_engine(struct xe_hw_engine *hwe) whitelist_apply_to_hwe(hwe, &hwe->oa_whitelist, &hwe->reg_sr, first_oa_slot); } +__maybe_unused static void __whitelist_oa_regs(struct xe_hw_engine *hwe, bool whitelist) +{ + struct xe_reg_sr_entry *entry; + unsigned long reg; + + xa_for_each(&hwe->oa_sr.xa, reg, entry) { + if (whitelist) + entry->set_bits &= ~RING_FORCE_TO_NONPRIV_DENY; + else + entry->set_bits |= RING_FORCE_TO_NONPRIV_DENY; + } + + xe_reg_sr_apply_mmio(&hwe->oa_sr, hwe->gt); +} + /** * xe_reg_whitelist_print_entry - print one whitelist entry * @p: DRM printer -- cgit v1.2.3 From 6f73bf8fffa728aa5d5ee143ba318fa0744113a2 Mon Sep 17 00:00:00 2001 From: Ashutosh Dixit Date: Mon, 15 Jun 2026 15:42:25 -0700 Subject: drm/xe/rtp: (De-)whitelist OA registers for all hwe's for a gt Whitelist or de-whitelist OA registers for all hwe's on the gt on which the OA stream is opened. This simplifies the case where an oa unit has 0 attached hwe's (but which monitors OA events on the associated GT). Fixes: 828a8eaf37c3 ("drm/xe/oa: Add MMIO trigger support") Cc: stable@vger.kernel.org # v6.12+ Signed-off-by: Ashutosh Dixit Reviewed-by: Umesh Nerlige Ramappa Link: https://patch.msgid.link/20260615224227.34880-8-ashutosh.dixit@intel.com --- drivers/gpu/drm/xe/xe_reg_whitelist.c | 32 +++++++++++++++++++++++++++++++- drivers/gpu/drm/xe/xe_reg_whitelist.h | 4 ++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.c b/drivers/gpu/drm/xe/xe_reg_whitelist.c index 7186998df498..b2e7aabd19d7 100644 --- a/drivers/gpu/drm/xe/xe_reg_whitelist.c +++ b/drivers/gpu/drm/xe/xe_reg_whitelist.c @@ -229,7 +229,7 @@ void xe_reg_whitelist_process_engine(struct xe_hw_engine *hwe) whitelist_apply_to_hwe(hwe, &hwe->oa_whitelist, &hwe->reg_sr, first_oa_slot); } -__maybe_unused static void __whitelist_oa_regs(struct xe_hw_engine *hwe, bool whitelist) +static void __whitelist_oa_regs(struct xe_hw_engine *hwe, bool whitelist) { struct xe_reg_sr_entry *entry; unsigned long reg; @@ -244,6 +244,36 @@ __maybe_unused static void __whitelist_oa_regs(struct xe_hw_engine *hwe, bool wh xe_reg_sr_apply_mmio(&hwe->oa_sr, hwe->gt); } +/** + * xe_reg_whitelist_oa_regs - whitelist oa registers for gt + * @gt: gt to whitelist oa registers for + * + * Whitelist OA registers by resetting RING_FORCE_TO_NONPRIV_DENY + */ +void xe_reg_whitelist_oa_regs(struct xe_gt *gt) +{ + struct xe_hw_engine *hwe; + enum xe_hw_engine_id id; + + for_each_hw_engine(hwe, gt, id) + __whitelist_oa_regs(hwe, true); +} + +/** + * xe_reg_dewhitelist_oa_regs - dewhitelist oa registers for gt + * @gt: gt to dewhitelist oa registers for + * + * Dewhitelist OA registers by setting RING_FORCE_TO_NONPRIV_DENY + */ +void xe_reg_dewhitelist_oa_regs(struct xe_gt *gt) +{ + struct xe_hw_engine *hwe; + enum xe_hw_engine_id id; + + for_each_hw_engine(hwe, gt, id) + __whitelist_oa_regs(hwe, false); +} + /** * xe_reg_whitelist_print_entry - print one whitelist entry * @p: DRM printer diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.h b/drivers/gpu/drm/xe/xe_reg_whitelist.h index 3b64b42fe96e..e1eb1b7d5480 100644 --- a/drivers/gpu/drm/xe/xe_reg_whitelist.h +++ b/drivers/gpu/drm/xe/xe_reg_whitelist.h @@ -9,12 +9,16 @@ #include struct drm_printer; +struct xe_gt; struct xe_hw_engine; struct xe_reg_sr; struct xe_reg_sr_entry; void xe_reg_whitelist_process_engine(struct xe_hw_engine *hwe); +void xe_reg_whitelist_oa_regs(struct xe_gt *gt); +void xe_reg_dewhitelist_oa_regs(struct xe_gt *gt); + void xe_reg_whitelist_print_entry(struct drm_printer *p, unsigned int indent, u32 reg, struct xe_reg_sr_entry *entry); -- cgit v1.2.3 From f8e6874f46f19a6a2a0f24a81689f90641bb402a Mon Sep 17 00:00:00 2001 From: Ashutosh Dixit Date: Mon, 15 Jun 2026 15:42:26 -0700 Subject: drm/xe/oa: (De-)whitelist OA registers on OA stream open/release Whitelist OA registers on stream open and de-whitelist on stream close/release. Whitelisting is only done when 'stream->sample' is true. 'stream->sample' is only true when (a) xe_observation_paranoid is set to false by system admin, or (b) the process is perfmon_capable(). This therefore enforces the OA register whitelisting security requirements. Fixes: 828a8eaf37c3 ("drm/xe/oa: Add MMIO trigger support") Cc: stable@vger.kernel.org # v6.12+ Signed-off-by: Ashutosh Dixit Reviewed-by: Umesh Nerlige Ramappa Link: https://patch.msgid.link/20260615224227.34880-9-ashutosh.dixit@intel.com --- drivers/gpu/drm/xe/xe_oa.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_oa.c b/drivers/gpu/drm/xe/xe_oa.c index 9fbd21b0ef97..b3acbcd678b7 100644 --- a/drivers/gpu/drm/xe/xe_oa.c +++ b/drivers/gpu/drm/xe/xe_oa.c @@ -37,6 +37,7 @@ #include "xe_oa.h" #include "xe_observation.h" #include "xe_pm.h" +#include "xe_reg_whitelist.h" #include "xe_sched_job.h" #include "xe_sriov.h" #include "xe_sync.h" @@ -885,6 +886,9 @@ static void xe_oa_stream_destroy(struct xe_oa_stream *stream) mutex_destroy(&stream->stream_lock); + if (stream->sample) + xe_reg_dewhitelist_oa_regs(stream->gt); + xe_oa_disable_metric_set(stream); xe_exec_queue_put(stream->k_exec_q); @@ -1886,6 +1890,9 @@ static int xe_oa_stream_open_ioctl_locked(struct xe_oa *oa, goto err_disable; } + if (stream->sample) + xe_reg_whitelist_oa_regs(stream->gt); + /* Hold a reference on the drm device till stream_fd is released */ drm_dev_get(&stream->oa->xe->drm); -- cgit v1.2.3 From 645f1a2589bd4782e25490e5ecc05b7043c36cbf Mon Sep 17 00:00:00 2001 From: Ashutosh Dixit Date: Mon, 15 Jun 2026 15:42:27 -0700 Subject: drm/xe/rtp: Ensure locking/ref counting for OA whitelists Since multiple OA streams might be open in parallel on a gt, ensure that proper locking is in place. Also ensure that OA registers are whitelisted when the first OA stream is open and de-whitelisted after the last OA stream is closed. Fixes: 828a8eaf37c3 ("drm/xe/oa: Add MMIO trigger support") Cc: stable@vger.kernel.org # v6.12+ Signed-off-by: Ashutosh Dixit Reviewed-by: Umesh Nerlige Ramappa Link: https://patch.msgid.link/20260615224227.34880-10-ashutosh.dixit@intel.com --- drivers/gpu/drm/xe/xe_oa_types.h | 3 +++ drivers/gpu/drm/xe/xe_reg_whitelist.c | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_oa_types.h b/drivers/gpu/drm/xe/xe_oa_types.h index 3d9ec8490899..e876e9be92ba 100644 --- a/drivers/gpu/drm/xe/xe_oa_types.h +++ b/drivers/gpu/drm/xe/xe_oa_types.h @@ -126,6 +126,9 @@ struct xe_oa_gt { /** @oa_unit: array of oa_units */ struct xe_oa_unit *oa_unit; + + /** @whitelist_count: number of open streams for which oa registers are whitelisted */ + u32 whitelist_count; }; /** diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.c b/drivers/gpu/drm/xe/xe_reg_whitelist.c index b2e7aabd19d7..3d9e3daab01a 100644 --- a/drivers/gpu/drm/xe/xe_reg_whitelist.c +++ b/drivers/gpu/drm/xe/xe_reg_whitelist.c @@ -255,6 +255,10 @@ void xe_reg_whitelist_oa_regs(struct xe_gt *gt) struct xe_hw_engine *hwe; enum xe_hw_engine_id id; + lockdep_assert_held(>->oa.gt_lock); + if (gt->oa.whitelist_count++) + return; + for_each_hw_engine(hwe, gt, id) __whitelist_oa_regs(hwe, true); } @@ -270,6 +274,11 @@ void xe_reg_dewhitelist_oa_regs(struct xe_gt *gt) struct xe_hw_engine *hwe; enum xe_hw_engine_id id; + lockdep_assert_held(>->oa.gt_lock); + xe_assert(gt_to_xe(gt), gt->oa.whitelist_count); + if (--gt->oa.whitelist_count) + return; + for_each_hw_engine(hwe, gt, id) __whitelist_oa_regs(hwe, false); } -- cgit v1.2.3 From 632cdeecdd30337e3a9293d9de52ad9fbaf5f229 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 22 Jun 2026 15:23:37 +0200 Subject: drm/xe/mmio: Verify MMIO is available We shouldn't access device registers after the device was unplugged or the MMIO bar (GTTMMADR) was unmapped. Instead of relying on the NPD splat due to zeroed tile->mmio.regs, which might be unreliable anyway as not all xe_mmio structs are using that directly, add an explicit check during all xe_mmio read/write operations to test if xe->mmio.regs are still mapped and safely abort with WARN if not. Signed-off-by: Michal Wajdeczko Cc: Matthew Auld Reviewed-by: Matthew Auld Link: https://patch.msgid.link/20260622132342.19600-2-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_mmio.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_mmio.c b/drivers/gpu/drm/xe/xe_mmio.c index 78adb303b663..7e0cefcd16bd 100644 --- a/drivers/gpu/drm/xe/xe_mmio.c +++ b/drivers/gpu/drm/xe/xe_mmio.c @@ -17,6 +17,7 @@ #include "xe_device.h" #include "xe_gt_sriov_vf.h" #include "xe_sriov.h" +#include "xe_tile_printk.h" #include "xe_trace.h" #include "xe_wa.h" @@ -128,6 +129,11 @@ void xe_mmio_init(struct xe_mmio *mmio, struct xe_tile *tile, void __iomem *ptr, mmio->tile = tile; } +static bool mmio_available(struct xe_mmio *mmio) +{ + return !xe_tile_WARN_ON_ONCE(mmio->tile, !mmio->tile->xe->mmio.regs); +} + static void mmio_flush_pending_writes(struct xe_mmio *mmio) { #define DUMMY_REG_OFFSET 0x130030 @@ -146,6 +152,9 @@ u8 xe_mmio_read8(struct xe_mmio *mmio, struct xe_reg reg) u32 addr = xe_mmio_adjusted_addr(mmio, reg.addr); u8 val; + if (!mmio_available(mmio)) + return 0; + mmio_flush_pending_writes(mmio); val = readb(mmio->regs + addr); @@ -158,6 +167,9 @@ void xe_mmio_write8(struct xe_mmio *mmio, struct xe_reg reg, u8 val) { u32 addr = xe_mmio_adjusted_addr(mmio, reg.addr); + if (!mmio_available(mmio)) + return; + trace_xe_reg_rw(mmio, true, addr, val, sizeof(val)); writeb(val, mmio->regs + addr); @@ -168,6 +180,9 @@ u16 xe_mmio_read16(struct xe_mmio *mmio, struct xe_reg reg) u32 addr = xe_mmio_adjusted_addr(mmio, reg.addr); u16 val; + if (!mmio_available(mmio)) + return 0; + mmio_flush_pending_writes(mmio); val = readw(mmio->regs + addr); @@ -180,6 +195,9 @@ void xe_mmio_write32(struct xe_mmio *mmio, struct xe_reg reg, u32 val) { u32 addr = xe_mmio_adjusted_addr(mmio, reg.addr); + if (!mmio_available(mmio)) + return; + trace_xe_reg_rw(mmio, true, addr, val, sizeof(val)); if (!reg.vf && IS_SRIOV_VF(mmio->tile->xe)) @@ -194,6 +212,9 @@ u32 xe_mmio_read32(struct xe_mmio *mmio, struct xe_reg reg) u32 addr = xe_mmio_adjusted_addr(mmio, reg.addr); u32 val; + if (!mmio_available(mmio)) + return 0; + mmio_flush_pending_writes(mmio); if (!reg.vf && IS_SRIOV_VF(mmio->tile->xe)) -- cgit v1.2.3 From f8c64537f2db36f1ccaf223c313b5590fd9ba411 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 22 Jun 2026 15:23:38 +0200 Subject: drm/xe/mmio: Map MMIO BAR using managed version of pci_iomap This will allow us to simplify our custom release action where we will keep only zeroing of the xe->mmio.regs as we still rely on it all checks during all xe_mmio operations. While around, add missing kernel-doc for the function and update the error message. Signed-off-by: Michal Wajdeczko Cc: Matthew Auld Reviewed-by: Matthew Auld Link: https://patch.msgid.link/20260622132342.19600-3-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_mmio.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_mmio.c b/drivers/gpu/drm/xe/xe_mmio.c index 7e0cefcd16bd..fce890b6410c 100644 --- a/drivers/gpu/drm/xe/xe_mmio.c +++ b/drivers/gpu/drm/xe/xe_mmio.c @@ -16,6 +16,7 @@ #include "regs/xe_bars.h" #include "xe_device.h" #include "xe_gt_sriov_vf.h" +#include "xe_printk.h" #include "xe_sriov.h" #include "xe_tile_printk.h" #include "xe_trace.h" @@ -80,27 +81,30 @@ int xe_mmio_probe_tiles(struct xe_device *xe) static void mmio_fini(void *arg) { struct xe_device *xe = arg; - struct xe_tile *root_tile = xe_device_get_root_tile(xe); - pci_iounmap(to_pci_dev(xe->drm.dev), xe->mmio.regs); xe->mmio.regs = NULL; - root_tile->mmio.regs = NULL; } +/** + * xe_mmio_probe_early() - Probe and initialize device's MMIO + * @xe: the &xe_device + * + * Map the entire GTTMMADR_BAR and initialize the first tile's MMIO instance. + * + * The first 16MB of the GTTMMADR_BAR always belongs to the root tile, and + * includes: registers (0-4MB), reserved space (4MB-8MB) and GGTT (8MB-16MB). + * + * Return: 0 on success or a negative error code on failure. + */ int xe_mmio_probe_early(struct xe_device *xe) { struct xe_tile *root_tile = xe_device_get_root_tile(xe); struct pci_dev *pdev = to_pci_dev(xe->drm.dev); - /* - * Map the entire BAR. - * The first 16MB of the BAR, belong to the root tile, and include: - * registers (0-4MB), reserved space (4MB-8MB) and GGTT (8MB-16MB). - */ xe->mmio.size = pci_resource_len(pdev, GTTMMADR_BAR); - xe->mmio.regs = pci_iomap(pdev, GTTMMADR_BAR, 0); + xe->mmio.regs = pcim_iomap(pdev, GTTMMADR_BAR, 0); if (!xe->mmio.regs) { - drm_err(&xe->drm, "failed to map registers\n"); + xe_err(xe, "Failed to map GTTMMADR_BAR\n"); return -EIO; } -- cgit v1.2.3 From 16bc4493bbf3be76b08e980b2f2380987c3ac9f4 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 22 Jun 2026 15:23:39 +0200 Subject: drm/xe/mmio: Add check for minimal BAR size We initialized the root tile's xe_mmio structure with a new size of 4MiB without sanity checks to see if mapped GTTMMADR_BAR was actually at least that size. Check BAR size against first 16MiB, which is expected minimum BAR size for the one-tile platforms. Signed-off-by: Michal Wajdeczko Reviewed-by: Matthew Auld Link: https://patch.msgid.link/20260622132342.19600-4-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_mmio.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_mmio.c b/drivers/gpu/drm/xe/xe_mmio.c index fce890b6410c..8dd818e1184c 100644 --- a/drivers/gpu/drm/xe/xe_mmio.c +++ b/drivers/gpu/drm/xe/xe_mmio.c @@ -101,13 +101,18 @@ int xe_mmio_probe_early(struct xe_device *xe) struct xe_tile *root_tile = xe_device_get_root_tile(xe); struct pci_dev *pdev = to_pci_dev(xe->drm.dev); - xe->mmio.size = pci_resource_len(pdev, GTTMMADR_BAR); xe->mmio.regs = pcim_iomap(pdev, GTTMMADR_BAR, 0); if (!xe->mmio.regs) { xe_err(xe, "Failed to map GTTMMADR_BAR\n"); return -EIO; } + xe->mmio.size = pci_resource_len(pdev, GTTMMADR_BAR); + if (xe->mmio.size < SZ_16M) { + xe_err(xe, "GTTMMADR_BAR is too small: %zu\n", xe->mmio.size); + return -EIO; + } + /* Setup first tile; other tiles (if present) will be setup later. */ xe_mmio_init(&root_tile->mmio, root_tile, xe->mmio.regs, SZ_4M); -- cgit v1.2.3 From 82b117980acdc1651b51ccb1f2af6becb350daf7 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 22 Jun 2026 15:23:40 +0200 Subject: drm/xe/mmio: Drop tiles_fini action The pointer zeroing is not required, as we check xe->mmio.regs to test if code is not trying to access MMIO after a driver unwind. Signed-off-by: Michal Wajdeczko Cc: Matthew Auld Reviewed-by: Matthew Auld Link: https://patch.msgid.link/20260622132342.19600-5-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_mmio.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_mmio.c b/drivers/gpu/drm/xe/xe_mmio.c index 8dd818e1184c..58226cd8b399 100644 --- a/drivers/gpu/drm/xe/xe_mmio.c +++ b/drivers/gpu/drm/xe/xe_mmio.c @@ -24,16 +24,6 @@ #include "generated/xe_device_wa_oob.h" -static void tiles_fini(void *arg) -{ - struct xe_device *xe = arg; - struct xe_tile *tile; - int id; - - for_each_remote_tile(tile, xe, id) - tile->mmio.regs = NULL; -} - /* * On multi-tile devices, partition the BAR space for MMIO on each tile, * possibly accounting for register override on the number of tiles available. @@ -74,8 +64,7 @@ int xe_mmio_probe_tiles(struct xe_device *xe) size_t tile_mmio_size = SZ_16M; mmio_multi_tile_setup(xe, tile_mmio_size); - - return devm_add_action_or_reset(xe->drm.dev, tiles_fini, xe); + return 0; } static void mmio_fini(void *arg) -- cgit v1.2.3 From 699ca9d4ec71e74c40e394bfa7616b56c82279fa Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 22 Jun 2026 15:23:41 +0200 Subject: drm/xe/mmio: Check MMIO BAR size when initializing tiles We initialized all remote tiles' xe_mmio structures with a new size of 4MiB and offsets of 16MiB without sanity checks to see if mapped GTTMMADR_BAR was actually at least that size. Signed-off-by: Michal Wajdeczko Reviewed-by: Matthew Auld Link: https://patch.msgid.link/20260622132342.19600-6-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_mmio.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_mmio.c b/drivers/gpu/drm/xe/xe_mmio.c index 58226cd8b399..41e6b753634f 100644 --- a/drivers/gpu/drm/xe/xe_mmio.c +++ b/drivers/gpu/drm/xe/xe_mmio.c @@ -48,21 +48,35 @@ static void mmio_multi_tile_setup(struct xe_device *xe, size_t tile_mmio_size) struct xe_tile *tile; u8 id; - /* - * Nothing to be done as tile 0 has already been setup earlier with the - * entire BAR mapped - see xe_mmio_probe_early() - */ - if (xe->info.tile_count == 1) - return; - for_each_remote_tile(tile, xe, id) xe_mmio_init(&tile->mmio, tile, xe->mmio.regs + id * tile_mmio_size, SZ_4M); } +/** + * xe_mmio_probe_tiles() - Initialize all tiles' MMIO + * @xe: the &xe_device + * + * Initialize the remaining tiles' MMIO instances. + * + * Return: 0 on success or a negative error code on failure. + */ int xe_mmio_probe_tiles(struct xe_device *xe) { size_t tile_mmio_size = SZ_16M; + /* + * Nothing to be done as tile 0 has already been setup earlier with the + * entire BAR mapped - see xe_mmio_probe_early() + */ + if (xe->info.tile_count == 1) + return 0; + + if (xe->mmio.size < xe->info.tile_count * tile_mmio_size) { + xe_err(xe, "GTTMMADR_BAR is too small for %d tiles: %zu\n", + xe->info.tile_count, xe->mmio.size); + return -EIO; + } + mmio_multi_tile_setup(xe, tile_mmio_size); return 0; } -- cgit v1.2.3 From 692689c97bbb99f191926ec596c9193d95189702 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 22 Jun 2026 15:23:42 +0200 Subject: drm/xe/mmio: Prefer tile-based WARN message If 64-bit read operations are unstable, use tile-based WARN message to provide more details on which tile this was observed. Signed-off-by: Michal Wajdeczko Reviewed-by: Matthew Auld Link: https://patch.msgid.link/20260622132342.19600-7-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_mmio.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_mmio.c b/drivers/gpu/drm/xe/xe_mmio.c index 41e6b753634f..7fa18dfcb5a2 100644 --- a/drivers/gpu/drm/xe/xe_mmio.c +++ b/drivers/gpu/drm/xe/xe_mmio.c @@ -11,7 +11,6 @@ #include #include -#include #include "regs/xe_bars.h" #include "xe_device.h" @@ -315,8 +314,8 @@ u64 xe_mmio_read64_2x32(struct xe_mmio *mmio, struct xe_reg reg) oldudw = udw; } - drm_WARN(&mmio->tile->xe->drm, retries == 0, - "64-bit read of %#x did not stabilize\n", reg.addr); + xe_tile_WARN(mmio->tile, retries == 0, + "MMIO: 64-bit read of %#x did not stabilize\n", reg.addr); return (u64)udw << 32 | ldw; } -- cgit v1.2.3 From c4508edb2c723de93717272488ea65b165637eac Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Wed, 17 Jun 2026 06:51:01 -0700 Subject: drm/xe: Return error on non-migratable faults requiring devmem Non-migratable faults that require devmem incorrectly jump to the 'out' label, which squashes the error code intended to be returned to the upper layers. Fix this by returning -EACCES instead. Reported-by: Sashiko Fixes: 4208fac3dce5 ("drm/xe: Add more SVM GT stats") Cc: stable@vger.kernel.org Signed-off-by: Matthew Brost Reviewed-by: Francois Dugast Link: https://patch.msgid.link/20260617135101.1245574-1-matthew.brost@intel.com --- drivers/gpu/drm/xe/xe_svm.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c index e1651e70c8f0..b1e1ac26c66d 100644 --- a/drivers/gpu/drm/xe/xe_svm.c +++ b/drivers/gpu/drm/xe/xe_svm.c @@ -1248,10 +1248,8 @@ retry: xe_svm_range_fault_count_stats_incr(gt, range); - if (ctx.devmem_only && !range->base.pages.flags.migrate_devmem) { - err = -EACCES; - goto out; - } + if (ctx.devmem_only && !range->base.pages.flags.migrate_devmem) + return -EACCES; if (xe_svm_range_is_valid(range, tile, ctx.devmem_only, dpagemap)) { xe_svm_range_valid_fault_count_stats_incr(gt, range); -- cgit v1.2.3 From 3e493f88c84088ccd7b53cdd23ac5c875c9a60dd Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Fri, 12 Jun 2026 18:05:02 +0100 Subject: drm/xe/display: skip FORCE_WC and vm_bound check for external dma-bufs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, xe_display_bo_framebuffer_init() unconditionally attempts to apply XE_BO_FLAG_FORCE_WC to the buffer and rejects the FB creation with -EINVAL if the BO is already VM_BINDed. However, for imported dma-bufs (ttm_bo_type_sg), this check doesn't seem to make much sense since CPU caching policy is entirely controlled by the exporter. Plus there is no place to set this flag, in the first place. Also this is not rejected if not yet vm_binded, but that seems arbitrary since setting or not setting FORCE_WC should a noop either way, at this stage, and whether it is currently VM_BINDed makes no difference. Currently if we run an app and offload rendering to an external dGPU, like NV or another xe device, the dma-buf passed back to the compositor (igpu) will be an actual external import from xe pov, and it will be missing FORCE_WC, and if the compositor side did a VM_BIND before turning into it into an fb the whole thing gets rejected. So it looks like we either need to reject outright, no matter what, or this usecase is valid and we need to loosen the restriction for sg buffers. Proposing here to loosen the restriction. Assisted-by: Gemini:gemini-3.1-pro-preview Link: https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/7919 Fixes: 44e694958b95 ("drm/xe/display: Implement display support") Signed-off-by: Matthew Auld Cc: Thomas Hellström Cc: Matthew Brost Cc: Maarten Lankhorst Cc: # v6.12+ Reviewed-by: Maarten Lankhorst Link: https://patch.msgid.link/20260612170501.550816-2-matthew.auld@intel.com --- drivers/gpu/drm/xe/display/xe_display_bo.c | 3 ++- drivers/gpu/drm/xe/display/xe_fb_pin.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/display/xe_display_bo.c b/drivers/gpu/drm/xe/display/xe_display_bo.c index 7fbac223b097..8953da0136dc 100644 --- a/drivers/gpu/drm/xe/display/xe_display_bo.c +++ b/drivers/gpu/drm/xe/display/xe_display_bo.c @@ -48,7 +48,8 @@ static int xe_display_bo_framebuffer_init(struct drm_gem_object *obj, if (ret) goto err; - if (!(bo->flags & XE_BO_FLAG_FORCE_WC)) { + if (!(bo->flags & XE_BO_FLAG_FORCE_WC) && + bo->ttm.type != ttm_bo_type_sg) { /* * XE_BO_FLAG_FORCE_WC should ideally be set at creation, or is * automatically set when creating FB. We cannot change caching diff --git a/drivers/gpu/drm/xe/display/xe_fb_pin.c b/drivers/gpu/drm/xe/display/xe_fb_pin.c index f93c98bec5b5..5f4a0cd8deca 100644 --- a/drivers/gpu/drm/xe/display/xe_fb_pin.c +++ b/drivers/gpu/drm/xe/display/xe_fb_pin.c @@ -331,7 +331,8 @@ static struct i915_vma *__xe_pin_fb_vma(struct drm_gem_object *obj, bool is_dpt, int ret = 0; /* We reject creating !SCANOUT fb's, so this is weird.. */ - drm_WARN_ON(bo->ttm.base.dev, !(bo->flags & XE_BO_FLAG_FORCE_WC)); + drm_WARN_ON(bo->ttm.base.dev, !(bo->flags & XE_BO_FLAG_FORCE_WC) && + bo->ttm.type != ttm_bo_type_sg); if (!vma) return ERR_PTR(-ENODEV); -- cgit v1.2.3 From 80ccbd97ffee8ad2e73167d826fe7be548364365 Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Thu, 25 Jun 2026 21:56:15 +0000 Subject: drm/xe/userptr: Hold notifier_lock for write on inject test path When CONFIG_DRM_XE_USERPTR_INVAL_INJECT=y, xe_pt_svm_userptr_pre_commit() runs vma_check_userptr() with the svm notifier_lock taken for read. The test injection causes vma_check_userptr() to call xe_vma_userptr_force_invalidate(), which feeds into xe_vma_userptr_do_inval() with drm_gpusvm_ctx.in_notifier=true. That flag tells drm_gpusvm_unmap_pages() the caller already holds notifier_lock for write and only asserts the mode. Because the caller actually holds it for read, the assertion fires: WARNING: drivers/gpu/drm/drm_gpusvm.c:1669 at \ drm_gpusvm_unmap_pages+0xd4/0x130 [drm_gpusvm_helper] Call Trace: xe_vma_userptr_do_inval+0x40d/0xfd0 [xe] xe_vma_userptr_invalidate_pass1+0x3e6/0x8d0 [xe] xe_vma_userptr_force_invalidate+0xde/0x290 [xe] vma_check_userptr.constprop.0+0x1c6/0x220 [xe] xe_pt_svm_userptr_pre_commit+0x6a3/0xc60 [xe] ... xe_vm_bind_ioctl+0x3a0a/0x4480 [xe] Acquire notifier_lock for write in pre-commit when the inject Kconfig is enabled, via new helpers xe_pt_svm_userptr_notifier_lock()/_unlock(). Rename xe_svm_assert_held_read() to xe_svm_assert_held_read_or_inject_write() so it asserts the correct mode under each build configuration. Production builds (CONFIG_DRM_XE_USERPTR_INVAL_INJECT=n) keep the existing read-mode behavior bit-for-bit. Fixes: 9e9787414882 ("drm/xe/userptr: replace xe_hmm with gpusvm") Assisted-by: Claude:claude-opus-4.7 Cc: Matthew Auld Cc: Zongyao Bai Reviewed-by: Matthew Brost Link: https://patch.msgid.link/20260625215615.3016892-1-shuicheng.lin@intel.com Signed-off-by: Shuicheng Lin --- drivers/gpu/drm/xe/xe_pt.c | 43 +++++++++++++++++++++++++++++++++++-------- drivers/gpu/drm/xe/xe_svm.h | 15 +++++++++++++-- 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c index 0959e0e88a14..4f0f438d6b9b 100644 --- a/drivers/gpu/drm/xe/xe_pt.c +++ b/drivers/gpu/drm/xe/xe_pt.c @@ -1086,7 +1086,7 @@ static void xe_pt_commit_locks_assert(struct xe_vma *vma) xe_pt_commit_prepare_locks_assert(vma); if (xe_vma_is_userptr(vma)) - xe_svm_assert_held_read(vm); + xe_svm_assert_held_read_or_inject_write(vm); } static void xe_pt_commit(struct xe_vma *vma, @@ -1406,6 +1406,33 @@ static int xe_pt_pre_commit(struct xe_migrate_pt_update *pt_update) pt_update_ops, rftree); } +/* + * Acquire/release the svm notifier_lock around xe_pt_svm_userptr_pre_commit() + * and the matching late release in xe_pt_update_ops_run(). Read mode by + * default; write mode when CONFIG_DRM_XE_USERPTR_INVAL_INJECT is on, + * because a userptr op in this critical section may invoke the injected + * xe_vma_userptr_force_invalidate() path that calls + * drm_gpusvm_unmap_pages() with ctx->in_notifier=true, which requires the + * lock held for write. + */ +static void xe_pt_svm_userptr_notifier_lock(struct xe_vm *vm) +{ +#if IS_ENABLED(CONFIG_DRM_XE_USERPTR_INVAL_INJECT) + down_write(&vm->svm.gpusvm.notifier_lock); +#else + xe_svm_notifier_lock(vm); +#endif +} + +static void xe_pt_svm_userptr_notifier_unlock(struct xe_vm *vm) +{ +#if IS_ENABLED(CONFIG_DRM_XE_USERPTR_INVAL_INJECT) + up_write(&vm->svm.gpusvm.notifier_lock); +#else + xe_svm_notifier_unlock(vm); +#endif +} + #if IS_ENABLED(CONFIG_DRM_GPUSVM) #ifdef CONFIG_DRM_XE_USERPTR_INVAL_INJECT @@ -1437,7 +1464,7 @@ static int vma_check_userptr(struct xe_vm *vm, struct xe_vma *vma, struct xe_userptr_vma *uvma; unsigned long notifier_seq; - xe_svm_assert_held_read(vm); + xe_svm_assert_held_read_or_inject_write(vm); if (!xe_vma_is_userptr(vma)) return 0; @@ -1467,7 +1494,7 @@ static int op_check_svm_userptr(struct xe_vm *vm, struct xe_vma_op *op, { int err = 0; - xe_svm_assert_held_read(vm); + xe_svm_assert_held_read_or_inject_write(vm); switch (op->base.op) { case DRM_GPUVA_OP_MAP: @@ -1539,12 +1566,12 @@ static int xe_pt_svm_userptr_pre_commit(struct xe_migrate_pt_update *pt_update) if (err) return err; - xe_svm_notifier_lock(vm); + xe_pt_svm_userptr_notifier_lock(vm); list_for_each_entry(op, &vops->list, link) { err = op_check_svm_userptr(vm, op, pt_update_ops); if (err) { - xe_svm_notifier_unlock(vm); + xe_pt_svm_userptr_notifier_unlock(vm); break; } } @@ -2409,7 +2436,7 @@ static void bind_op_commit(struct xe_vm *vm, struct xe_tile *tile, vma->tile_invalidated & ~BIT(tile->id)); vma->tile_staged &= ~BIT(tile->id); if (xe_vma_is_userptr(vma)) { - xe_svm_assert_held_read(vm); + xe_svm_assert_held_read_or_inject_write(vm); to_userptr_vma(vma)->userptr.initial_bind = true; } @@ -2445,7 +2472,7 @@ static void unbind_op_commit(struct xe_vm *vm, struct xe_tile *tile, if (!vma->tile_present) { list_del_init(&vma->combined_links.rebind); if (xe_vma_is_userptr(vma)) { - xe_svm_assert_held_read(vm); + xe_svm_assert_held_read_or_inject_write(vm); spin_lock(&vm->userptr.invalidated_lock); list_del_init(&to_userptr_vma(vma)->userptr.invalidate_link); @@ -2721,7 +2748,7 @@ xe_pt_update_ops_run(struct xe_tile *tile, struct xe_vma_ops *vops) } if (pt_update_ops->needs_svm_lock) - xe_svm_notifier_unlock(vm); + xe_pt_svm_userptr_notifier_unlock(vm); /* * The last fence is only used for zero bind queue idling; migrate diff --git a/drivers/gpu/drm/xe/xe_svm.h b/drivers/gpu/drm/xe/xe_svm.h index b7b8eeacf196..3ca46a6f98c7 100644 --- a/drivers/gpu/drm/xe/xe_svm.h +++ b/drivers/gpu/drm/xe/xe_svm.h @@ -394,8 +394,19 @@ static inline struct drm_pagemap *xe_drm_pagemap_from_fd(int fd, u32 region_inst #define xe_svm_assert_in_notifier(vm__) \ lockdep_assert_held_write(&(vm__)->svm.gpusvm.notifier_lock) -#define xe_svm_assert_held_read(vm__) \ +/* + * Assert the svm notifier_lock is held. Read mode by default; write mode + * when CONFIG_DRM_XE_USERPTR_INVAL_INJECT is on, because that path forces + * a userptr invalidation that ends in drm_gpusvm_unmap_pages() with + * ctx->in_notifier=true, which requires the lock held for write. + */ +#if IS_ENABLED(CONFIG_DRM_XE_USERPTR_INVAL_INJECT) +#define xe_svm_assert_held_read_or_inject_write(vm__) \ + lockdep_assert_held_write(&(vm__)->svm.gpusvm.notifier_lock) +#else +#define xe_svm_assert_held_read_or_inject_write(vm__) \ lockdep_assert_held_read(&(vm__)->svm.gpusvm.notifier_lock) +#endif #define xe_svm_notifier_lock(vm__) \ drm_gpusvm_notifier_lock(&(vm__)->svm.gpusvm) @@ -409,7 +420,7 @@ static inline struct drm_pagemap *xe_drm_pagemap_from_fd(int fd, u32 region_inst #else #define xe_svm_assert_in_notifier(...) do {} while (0) -static inline void xe_svm_assert_held_read(struct xe_vm *vm) +static inline void xe_svm_assert_held_read_or_inject_write(struct xe_vm *vm) { } -- cgit v1.2.3 From ed382e3b07fae51a09d7290485bff0592f6b168b Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Thu, 25 Jun 2026 22:44:52 +0000 Subject: drm/xe/userptr: Drop bogus static from finish in force_invalidate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The local "finish" pointer in xe_vma_userptr_force_invalidate() is unconditionally written before each read, so the static storage class serves no purpose. Worse, it makes the variable a process-wide shared slot: the function's per-VM asserts do not exclude concurrent callers on different VMs, so two such callers can race on the slot and take the wrong if (finish) branch. The function is gated by CONFIG_DRM_XE_USERPTR_INVAL_INJECT (developer/test option, default n), so production builds are unaffected. Drop the static. Fixes: 18c4e536959e ("drm/xe/userptr: Convert invalidation to two-pass MMU notifier") Assisted-by: Claude:claude-opus-4.7 Cc: Thomas Hellström Cc: Matthew Brost Reviewed-by: Matthew Brost Reviewed-by: Zongyao Bai Link: https://patch.msgid.link/20260625224452.3243231-1-shuicheng.lin@intel.com Signed-off-by: Shuicheng Lin --- drivers/gpu/drm/xe/xe_userptr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_userptr.c b/drivers/gpu/drm/xe/xe_userptr.c index 6761005c0b90..6f71bc66b14e 100644 --- a/drivers/gpu/drm/xe/xe_userptr.c +++ b/drivers/gpu/drm/xe/xe_userptr.c @@ -269,7 +269,7 @@ static const struct mmu_interval_notifier_ops vma_userptr_notifier_ops = { */ void xe_vma_userptr_force_invalidate(struct xe_userptr_vma *uvma) { - static struct mmu_interval_notifier_finish *finish; + struct mmu_interval_notifier_finish *finish; struct xe_vm *vm = xe_vma_vm(&uvma->vma); /* Protect against concurrent userptr pinning */ -- cgit v1.2.3 From e459a3bdeb117be496d7f229e2ea1f6c9fe4080b Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Fri, 26 Jun 2026 21:06:31 +0000 Subject: drm/xe/hw_engine: Fix double-free of managed BO in error path The error path in hw_engine_init() explicitly frees a BO allocated with xe_managed_bo_create_pin_map() via xe_bo_unpin_map_no_vm(). Since the managed BO already has a devm cleanup action registered, this causes a double-free when devm unwinds during probe failure. Remove the explicit free and let devm handle it, consistent with all other xe_managed_bo_create_pin_map() callers. Fixes: 0e1a47fcabc8 ("drm/xe: Add a helper for DRM device-lifetime BO create") Assisted-by: Claude:claude-opus-4.6 Reviewed-by: Zongyao Bai Link: https://patch.msgid.link/20260626210631.3887291-1-shuicheng.lin@intel.com Signed-off-by: Shuicheng Lin --- drivers/gpu/drm/xe/xe_hw_engine.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c index 76aee461bcbe..87d60c4117bd 100644 --- a/drivers/gpu/drm/xe/xe_hw_engine.c +++ b/drivers/gpu/drm/xe/xe_hw_engine.c @@ -636,7 +636,7 @@ static int hw_engine_init(struct xe_gt *gt, struct xe_hw_engine *hwe, hwe->exl_port = xe_execlist_port_create(xe, hwe); if (IS_ERR(hwe->exl_port)) { err = PTR_ERR(hwe->exl_port); - goto err_hwsp; + goto err_name; } } else { /* GSCCS has a special interrupt for reset */ @@ -656,8 +656,6 @@ static int hw_engine_init(struct xe_gt *gt, struct xe_hw_engine *hwe, return devm_add_action_or_reset(xe->drm.dev, hw_engine_fini, hwe); -err_hwsp: - xe_bo_unpin_map_no_vm(hwe->hwsp); err_name: hwe->name = NULL; -- cgit v1.2.3 From 483c9f54515922398bd0dbca72c6194cd333685a Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 26 Jun 2026 14:53:28 -0700 Subject: drm/xe/tests/rtp: Add kunit test for whitelist upper bounds Xe must only add registers to the GT whitelist if they are listed in the "Software Allowlist" section of the bspec. These registers have been carefully reviewed by the architecture/security teams to ensure that they are safe to whitelist from a security perspective. The list of allowed registers changes from platform to platform, and it is not safe to assume that a register is safe to whitelist on a new platform/IP just because it was whitelisted on older ones. This means that whitelist entries in the driver that used undefined upper bounds (XE_RTP_END_VERSION_UNDEFINED) for their version ranges should always be considered illegal since they could potentially open unexpected security holes on future platforms. Add a kunit test to scan the whitelist RTP table and ensure that all entries have well-defined upper bounds on IP version ranges. Reviewed-by: Gustavo Sousa Link: https://patch.msgid.link/20260626-kunit_whitelist_bounds-v3-1-aedf0b3adab9@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c | 21 +++++++++++++++++++++ drivers/gpu/drm/xe/xe_reg_whitelist.c | 5 ++++- drivers/gpu/drm/xe/xe_reg_whitelist.h | 4 ++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c b/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c index ef379cbb6a86..7e2fc39ac62c 100644 --- a/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c +++ b/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c @@ -5,6 +5,7 @@ #include +#include "xe_reg_whitelist.h" #include "xe_rtp_types.h" #include "xe_tuning.h" #include "xe_wa.h" @@ -75,11 +76,31 @@ static void xe_rtp_table_dev_oob_test(struct kunit *test) RTP_TABLE_PARAM(device_oob_was); +static void xe_rtp_table_missing_upper_bound_test(struct kunit *test) +{ + const struct xe_rtp_entry_sr *entry = test->param_value; + + for (int i = 0; i < entry->n_rules; i++) { + u8 match_type = entry->rules[i].match_type; + + KUNIT_EXPECT_FALSE(test, + match_type == XE_RTP_MATCH_GRAPHICS_VERSION_RANGE && + entry->rules[i].ver_end == XE_RTP_END_VERSION_UNDEFINED); + KUNIT_EXPECT_FALSE(test, + match_type == XE_RTP_MATCH_MEDIA_VERSION_RANGE && + entry->rules[i].ver_end == XE_RTP_END_VERSION_UNDEFINED); + } +} + +RTP_TABLE_PARAM(register_whitelist); + static struct kunit_case xe_rtp_table_tests[] = { KUNIT_CASE_PARAM(xe_rtp_table_gt_test, gt_was_gen_params), KUNIT_CASE_PARAM(xe_rtp_table_gt_test, gt_tunings_gen_params), KUNIT_CASE_PARAM(xe_rtp_table_oob_test, oob_was_gen_params), KUNIT_CASE_PARAM(xe_rtp_table_dev_oob_test, device_oob_was_gen_params), + KUNIT_CASE_PARAM(xe_rtp_table_missing_upper_bound_test, + register_whitelist_gen_params), {} }; diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.c b/drivers/gpu/drm/xe/xe_reg_whitelist.c index 3d9e3daab01a..fe996d23007b 100644 --- a/drivers/gpu/drm/xe/xe_reg_whitelist.c +++ b/drivers/gpu/drm/xe/xe_reg_whitelist.c @@ -5,6 +5,8 @@ #include "xe_reg_whitelist.h" +#include + #include "regs/xe_engine_regs.h" #include "regs/xe_gt_regs.h" #include "regs/xe_oa_regs.h" @@ -41,7 +43,7 @@ static bool match_multi_queue_class(const struct xe_device *xe, return xe_gt_supports_multi_queue(gt, hwe->class); } -static const struct xe_rtp_table_sr register_whitelist = XE_RTP_TABLE_SR( +VISIBLE_IF_KUNIT const struct xe_rtp_table_sr register_whitelist = XE_RTP_TABLE_SR( { XE_RTP_NAME("WaAllowPMDepthAndInvocationCountAccessFromUMD, 1408556865"), XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 1210), ENGINE_CLASS(RENDER)), XE_RTP_ACTIONS(WHITELIST(PS_INVOCATION_COUNT, @@ -104,6 +106,7 @@ static const struct xe_rtp_table_sr register_whitelist = XE_RTP_TABLE_SR( RING_FORCE_TO_NONPRIV_ACCESS_RW)) }, ); +EXPORT_SYMBOL_IF_KUNIT(register_whitelist); static const struct xe_rtp_table_sr oa_whitelist = XE_RTP_TABLE_SR( diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.h b/drivers/gpu/drm/xe/xe_reg_whitelist.h index e1eb1b7d5480..c0248063d515 100644 --- a/drivers/gpu/drm/xe/xe_reg_whitelist.h +++ b/drivers/gpu/drm/xe/xe_reg_whitelist.h @@ -14,6 +14,10 @@ struct xe_hw_engine; struct xe_reg_sr; struct xe_reg_sr_entry; +#if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST) +extern const struct xe_rtp_table_sr register_whitelist; +#endif + void xe_reg_whitelist_process_engine(struct xe_hw_engine *hwe); void xe_reg_whitelist_oa_regs(struct xe_gt *gt); -- cgit v1.2.3 From b623bd790db04f5a6159838f2eeef7871c9a1062 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 26 Jun 2026 14:39:35 -0700 Subject: drm/xe: Drop 'force_execlist' module parameter During very early development of the Xe driver the force_execlist module parameter could be used to exercise some parts of the driver in a GuC-less manner. This was primarily intended to ensure that the driver was being designed and developed with proper modularity and layering; use of the GuC firmware has always been considered mandatory for any real Xe driver operation. The "execlist" implementation in the driver was never completed, and has further bitrotted over time to the point where it hangs during execution of even the simplest IGT tests like xe_exec_store now. Drop the force_execlist parameter; it's broken and isn't going to get fixed. In the (very unlikely) event that we decide to bring something like this back in the future, it would need to be as a per-device configfs setting rather than a driver-wide module parameter. The "execlist" implementation is now dead code, so it will probably also be removed sometime in the near future. There's a bit more general refactoring we might want to do first before we take that step, so for now we're just removing the module parameter. Reviewed-by: Maarten Lankhorst Link: https://patch.msgid.link/20260626-remove_execlists-v1-1-2584d8c4a6f2@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/xe_debugfs.c | 1 - drivers/gpu/drm/xe/xe_device.h | 2 +- drivers/gpu/drm/xe/xe_device_types.h | 2 -- drivers/gpu/drm/xe/xe_gt_mcr.c | 3 +-- drivers/gpu/drm/xe/xe_guc_tlb_inval.c | 6 ------ drivers/gpu/drm/xe/xe_module.c | 3 --- drivers/gpu/drm/xe/xe_module.h | 1 - drivers/gpu/drm/xe/xe_pci.c | 1 - 8 files changed, 2 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_debugfs.c b/drivers/gpu/drm/xe/xe_debugfs.c index 22b471303984..3c018dbccc07 100644 --- a/drivers/gpu/drm/xe/xe_debugfs.c +++ b/drivers/gpu/drm/xe/xe_debugfs.c @@ -117,7 +117,6 @@ static int info(struct seq_file *m, void *data) drm_printf(&p, "revid %d\n", xe->info.revid); drm_printf(&p, "tile_count %d\n", xe->info.tile_count); drm_printf(&p, "vm_max_level %d\n", xe->info.vm_max_level); - drm_printf(&p, "force_execlist %s\n", str_yes_no(xe->info.force_execlist)); drm_printf(&p, "has_flat_ccs %s\n", str_yes_no(xe->info.has_flat_ccs)); drm_printf(&p, "has_usm %s\n", str_yes_no(xe->info.has_usm)); drm_printf(&p, "skip_guc_pc %s\n", str_yes_no(xe->info.skip_guc_pc)); diff --git a/drivers/gpu/drm/xe/xe_device.h b/drivers/gpu/drm/xe/xe_device.h index 975768a6a9c8..8056d8bd7d6d 100644 --- a/drivers/gpu/drm/xe/xe_device.h +++ b/drivers/gpu/drm/xe/xe_device.h @@ -116,7 +116,7 @@ static inline struct xe_mmio *xe_root_tile_mmio(struct xe_device *xe) static inline bool xe_device_uc_enabled(struct xe_device *xe) { - return !xe->info.force_execlist; + return true; } #define for_each_tile(tile__, xe__, id__) \ diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index 4e2f115f14e2..46a9e9fad7a9 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -144,8 +144,6 @@ struct xe_device { * Keep all flags below alphabetically sorted */ - /** @info.force_execlist: Forced execlist submission */ - u8 force_execlist:1; /** @info.has_access_counter: Device supports access counter */ u8 has_access_counter:1; /** @info.has_asid: Has address space ID */ diff --git a/drivers/gpu/drm/xe/xe_gt_mcr.c b/drivers/gpu/drm/xe/xe_gt_mcr.c index d11cc9e25cdb..a97b236dab7c 100644 --- a/drivers/gpu/drm/xe/xe_gt_mcr.c +++ b/drivers/gpu/drm/xe/xe_gt_mcr.c @@ -404,8 +404,7 @@ fallback: * Some older platforms don't have tables or don't have complete tables. * Newer platforms should always have the required info. */ - if (GRAPHICS_VERx100(gt_to_xe(gt)) >= 2000 && - !gt_to_xe(gt)->info.force_execlist) + if (GRAPHICS_VERx100(gt_to_xe(gt)) >= 2000) xe_gt_err(gt, "Slice/Subslice counts missing from hwconfig table; using typical fallback values\n"); if (gt_to_xe(gt)->info.platform == XE_PVC) diff --git a/drivers/gpu/drm/xe/xe_guc_tlb_inval.c b/drivers/gpu/drm/xe/xe_guc_tlb_inval.c index cf6d106e6036..046d0655122f 100644 --- a/drivers/gpu/drm/xe/xe_guc_tlb_inval.c +++ b/drivers/gpu/drm/xe/xe_guc_tlb_inval.c @@ -208,9 +208,6 @@ static int send_tlb_inval_asid_ppgtt(struct xe_tlb_inval *tlb_inval, u32 seqno, lockdep_assert_held(&tlb_inval->seqno_lock); - if (guc_to_xe(guc)->info.force_execlist) - return -ECANCELED; - return send_tlb_inval_ppgtt(guc, seqno, start, end, asid, XE_GUC_TLB_INVAL_PAGE_SELECTIVE, prl_sa); } @@ -228,9 +225,6 @@ static int send_tlb_inval_ctx_ppgtt(struct xe_tlb_inval *tlb_inval, u32 seqno, lockdep_assert_held(&tlb_inval->seqno_lock); - if (xe->info.force_execlist) - return -ECANCELED; - vm = xe_device_asid_to_vm(xe, asid); if (IS_ERR(vm)) return PTR_ERR(vm); diff --git a/drivers/gpu/drm/xe/xe_module.c b/drivers/gpu/drm/xe/xe_module.c index 4cb578182912..39e4fc85f019 100644 --- a/drivers/gpu/drm/xe/xe_module.c +++ b/drivers/gpu/drm/xe/xe_module.c @@ -36,9 +36,6 @@ module_param_named(svm_notifier_size, xe_modparam.svm_notifier_size, uint, 0600) MODULE_PARM_DESC(svm_notifier_size, "Set the svm notifier size in MiB, must be power of 2 " "[default=" __stringify(XE_DEFAULT_SVM_NOTIFIER_SIZE) "]"); -module_param_named_unsafe(force_execlist, xe_modparam.force_execlist, bool, 0444); -MODULE_PARM_DESC(force_execlist, "Force Execlist submission"); - #if IS_ENABLED(CONFIG_DRM_XE_DISPLAY) module_param_named(probe_display, xe_modparam.probe_display, bool, 0444); MODULE_PARM_DESC(probe_display, "Probe display HW, otherwise it's left untouched " diff --git a/drivers/gpu/drm/xe/xe_module.h b/drivers/gpu/drm/xe/xe_module.h index 79cb9639c0f3..c75153471248 100644 --- a/drivers/gpu/drm/xe/xe_module.h +++ b/drivers/gpu/drm/xe/xe_module.h @@ -10,7 +10,6 @@ /* Module modprobe variables */ struct xe_modparam { - bool force_execlist; bool probe_display; int force_vram_bar_size; int guc_log_level; diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index c9d4fb6c4ff6..03362480e3e0 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -792,7 +792,6 @@ 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); -- cgit v1.2.3 From 1714d360fc5ae2e0886a69e979095d9c7ff3568a Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Wed, 27 May 2026 20:37:35 +0200 Subject: drm/xe/pf: Don't attempt to process FAST_REQ or EVENT relays MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently defined VF/PF relay actions use regular REQUEST messages only and the PF shouldn't attempt to handle FAST_REQUEST nor EVENT messages as this would result in breaking the VFPF ABI protocol and also might trigger an assert on the PF side. Fixes: 98e62805921c ("drm/xe/pf: Add SR-IOV GuC Relay PF services") Signed-off-by: Michal Wajdeczko Reviewed-by: Michał Winiarski Link: https://patch.msgid.link/20260527183735.22616-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_guc_relay.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_guc_relay.c b/drivers/gpu/drm/xe/xe_guc_relay.c index 577a315854af..eed0a750d2eb 100644 --- a/drivers/gpu/drm/xe/xe_guc_relay.c +++ b/drivers/gpu/drm/xe/xe_guc_relay.c @@ -689,12 +689,17 @@ static int relay_action_handler(struct xe_guc_relay *relay, u32 origin, return relay_testloop_action_handler(relay, origin, msg, len, response, size); type = FIELD_GET(GUC_HXG_MSG_0_TYPE, msg[0]); + relay_assert(relay, guc_hxg_type_is_action(type)); - if (IS_SRIOV_PF(relay_to_xe(relay))) - ret = xe_gt_sriov_pf_service_process_request(gt, origin, msg, len, response, size); - else + if (IS_SRIOV_PF(relay_to_xe(relay))) { + if (type == GUC_HXG_TYPE_REQUEST) + ret = xe_gt_sriov_pf_service_process_request(gt, origin, msg, len, + response, size); + else + ret = -EOPNOTSUPP; + } else { ret = -EOPNOTSUPP; - + } if (type == GUC_HXG_TYPE_EVENT) relay_assert(relay, ret <= 0); -- cgit v1.2.3 From c9a8e7daa0afe3161111e27fd92176e608c7f186 Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Thu, 25 Jun 2026 16:20:56 +0100 Subject: drm/xe: fix NPD in bo_meminfo() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a buffer object is purged, its ttm.resource is set to NULL via the TTM pipeline gutting flow. However, the BO remains in the client's object list until userspace explicitly closes the GEM handle. If memory stats are queried during this time, accessing bo->ttm.resource->mem_type will result in a NULL pointer dereference. Fix this by safely skipping purged BOs in bo_meminfo, as they no longer consume any memory. User is getting NPD on device resume, and possible theory is that in bo_move(), if we need to evict something to SYSTEM to save the CCS state, but the BO is marked as dontneed, this won't trigger a move but will nuke the pages, leaving us with a NULL bo resource. And the meminfo() doesn't look ready to handle a NULL resource. v2 (Sashiko): - There could potentially be other cases where we might end up with a NULL resource, so make this a general NULL check for now. Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/8419 Fixes: ad9843aac91a ("drm/xe/madvise: Implement purgeable buffer object support") Assisted-by: Copilot:gemini-3.1-pro-preview Reported-by: Matthew Schwartz Signed-off-by: Matthew Auld Cc: Thomas Hellström Cc: Matthew Brost Cc: Arvind Yadav Reviewed-by: Matthew Brost Tested-by: Matthew Schwartz Link: https://patch.msgid.link/20260625152054.450125-6-matthew.auld@intel.com --- drivers/gpu/drm/xe/xe_drm_client.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_drm_client.c b/drivers/gpu/drm/xe/xe_drm_client.c index 84b66147bf49..81020b4b344e 100644 --- a/drivers/gpu/drm/xe/xe_drm_client.c +++ b/drivers/gpu/drm/xe/xe_drm_client.c @@ -168,10 +168,20 @@ static void bo_meminfo(struct xe_bo *bo, struct drm_memory_stats stats[TTM_NUM_MEM_TYPES]) { u64 sz = xe_bo_size(bo); - u32 mem_type = bo->ttm.resource->mem_type; + u32 mem_type; xe_bo_assert_held(bo); + /* + * The resource can be NULL if the BO has been purged, plus maybe some + * other cases. Either way there shouldn't be any memory to account for, + * or a current resource to account this against, so skip for now. + */ + if (!bo->ttm.resource) + return; + + mem_type = bo->ttm.resource->mem_type; + if (drm_gem_object_is_shared_for_memory_stats(&bo->ttm.base)) stats[mem_type].shared += sz; else -- cgit v1.2.3 From cde38f5a5dbac84b57c05e8bc973fc4f63936ca4 Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Thu, 25 Jun 2026 16:20:57 +0100 Subject: drm/xe: account for dontneed in fdinfo purgeable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that Xe supports explicit madvise WILLNEED/DONTNEED states, userspace can mark memory in any placement as eligible for purging. Update bo_meminfo to also include any BO explicitly marked as DONTNEED in the purgeable statistics, ensuring fdinfo accurately reflects all memory offered up for reclamation. v2 (Sashiko): - Also update the drm_print_memory_stats() so we don't mask out != SYSTEM Assisted-by: Copilot:gemini-3.1-pro-preview Signed-off-by: Matthew Auld Cc: Thomas Hellström Cc: Matthew Brost Cc: Arvind Yadav Reviewed-by: Matthew Brost Link: https://patch.msgid.link/20260625152054.450125-7-matthew.auld@intel.com --- drivers/gpu/drm/xe/xe_drm_client.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_drm_client.c b/drivers/gpu/drm/xe/xe_drm_client.c index 81020b4b344e..e116fb562c4c 100644 --- a/drivers/gpu/drm/xe/xe_drm_client.c +++ b/drivers/gpu/drm/xe/xe_drm_client.c @@ -193,7 +193,7 @@ static void bo_meminfo(struct xe_bo *bo, if (!dma_resv_test_signaled(bo->ttm.base.resv, DMA_RESV_USAGE_BOOKKEEP)) stats[mem_type].active += sz; - else if (mem_type == XE_PL_SYSTEM) + else if (mem_type == XE_PL_SYSTEM || xe_bo_madv_is_dontneed(bo)) stats[mem_type].purgeable += sz; } } @@ -273,8 +273,7 @@ static void show_meminfo(struct drm_printer *p, struct drm_file *file) &stats[mem_type], DRM_GEM_OBJECT_ACTIVE | DRM_GEM_OBJECT_RESIDENT | - (mem_type != XE_PL_SYSTEM ? 0 : - DRM_GEM_OBJECT_PURGEABLE), + DRM_GEM_OBJECT_PURGEABLE, xe_mem_type_to_name[mem_type]); } } -- cgit v1.2.3 From 4c7b9c6ece32440e5a435a92076d049450cd2d2e Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Thu, 25 Jun 2026 16:20:58 +0100 Subject: drm/xe/pt: prevent invalid cursor access for purged BOs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During a page table walk for binding, xe_pt_stage_bind() explicitly skips initializing the xe_res_cursor for purged BOs, treating them similarly to NULL VMAs by only setting the cursor size. However, xe_pt_hugepte_possible() and xe_pt_scan_64K() did not check if the BO was purged before attempting to walk the cursor using xe_res_dma() and xe_res_next(). Because the cursor was left uninitialized for purged BOs, this falls through and triggers warnings like: WARNING: drivers/gpu/drm/xe/xe_res_cursor.h:274 at xe_res_next Fix this by explicitly checking if the BO is purged in both xe_pt_hugepte_possible() and xe_pt_scan_64K(), returning early just as we do for NULL VMAs, avoiding the invalid cursor accesses entirely. As a precaution, also zero-initialize the cursor in xe_pt_stage_bind() to ensure we don't pass garbage data into the page table walkers if we ever hit a similar edge case in the future. Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/8418 Fixes: ad9843aac91a ("drm/xe/madvise: Implement purgeable buffer object support") Assisted-by: Copilot:gemini-3.1-pro-preview Reported-by: Matthew Schwartz Signed-off-by: Matthew Auld Cc: Thomas Hellström Cc: Matthew Brost Cc: Arvind Yadav Reviewed-by: Matthew Brost Tested-by: Matthew Schwartz Link: https://patch.msgid.link/20260625152054.450125-8-matthew.auld@intel.com --- drivers/gpu/drm/xe/xe_pt.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c index 4f0f438d6b9b..5e82fc28edfc 100644 --- a/drivers/gpu/drm/xe/xe_pt.c +++ b/drivers/gpu/drm/xe/xe_pt.c @@ -433,6 +433,7 @@ xe_pt_insert_entry(struct xe_pt_stage_bind_walk *xe_walk, struct xe_pt *parent, static bool xe_pt_hugepte_possible(u64 addr, u64 next, unsigned int level, struct xe_pt_stage_bind_walk *xe_walk) { + struct xe_bo *bo = xe_vma_bo(xe_walk->vma); u64 size, dma; if (level > MAX_HUGEPTE_LEVEL) @@ -446,8 +447,8 @@ static bool xe_pt_hugepte_possible(u64 addr, u64 next, unsigned int level, if (next - xe_walk->va_curs_start > xe_walk->curs->size) return false; - /* null VMA's do not have dma addresses */ - if (xe_vma_is_null(xe_walk->vma)) + /* null VMA's and purged BO's do not have dma addresses */ + if (xe_vma_is_null(xe_walk->vma) || (bo && xe_bo_is_purged(bo))) return true; /* if we are clearing page table, no dma addresses*/ @@ -468,6 +469,7 @@ static bool xe_pt_hugepte_possible(u64 addr, u64 next, unsigned int level, static bool xe_pt_scan_64K(u64 addr, u64 next, struct xe_pt_stage_bind_walk *xe_walk) { + struct xe_bo *bo = xe_vma_bo(xe_walk->vma); struct xe_res_cursor curs = *xe_walk->curs; if (!IS_ALIGNED(addr, SZ_64K)) @@ -476,8 +478,8 @@ xe_pt_scan_64K(u64 addr, u64 next, struct xe_pt_stage_bind_walk *xe_walk) if (next > xe_walk->l0_end_addr) return false; - /* null VMA's do not have dma addresses */ - if (xe_vma_is_null(xe_walk->vma)) + /* null VMA's and purged BO's do not have dma addresses */ + if (xe_vma_is_null(xe_walk->vma) || (bo && xe_bo_is_purged(bo))) return true; xe_res_next(&curs, addr - xe_walk->va_curs_start); @@ -708,7 +710,7 @@ xe_pt_stage_bind(struct xe_tile *tile, struct xe_vma *vma, { struct xe_device *xe = tile_to_xe(tile); struct xe_bo *bo = xe_vma_bo(vma); - struct xe_res_cursor curs; + struct xe_res_cursor curs = {}; struct xe_vm *vm = xe_vma_vm(vma); struct xe_pt_stage_bind_walk xe_walk = { .base = { -- cgit v1.2.3 From 9420abf8dbc2eddaaa144c6948615b2547c84fb6 Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Tue, 30 Jun 2026 14:48:00 +0530 Subject: drm/xe/i2c: Drop manual VF check Clear has_i2c flag inside vf_update_device_info() instead of manually checking for VF instance. Signed-off-by: Raag Jadav Reviewed-by: Heikki Krogerus Reviewed-by: Michal Wajdeczko Signed-off-by: Michal Wajdeczko Link: https://patch.msgid.link/20260630091800.403926-1-raag.jadav@intel.com --- drivers/gpu/drm/xe/xe_device.c | 1 + drivers/gpu/drm/xe/xe_i2c.c | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index d3fbcf10f8ab..c9fa4bfed2b9 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -739,6 +739,7 @@ static void vf_update_device_info(struct xe_device *xe) xe->info.probe_display = 0; xe->info.has_heci_cscfi = 0; xe->info.has_heci_gscfi = 0; + xe->info.has_i2c = 0; xe->info.has_late_bind = 0; xe->info.skip_guc_pc = 1; xe->info.skip_pcode = 1; diff --git a/drivers/gpu/drm/xe/xe_i2c.c b/drivers/gpu/drm/xe/xe_i2c.c index 706783863d07..bd956776b10b 100644 --- a/drivers/gpu/drm/xe/xe_i2c.c +++ b/drivers/gpu/drm/xe/xe_i2c.c @@ -334,9 +334,6 @@ int xe_i2c_probe(struct xe_device *xe) if (!xe->info.has_i2c) return 0; - if (IS_SRIOV_VF(xe)) - return 0; - xe_i2c_read_endpoint(xe_root_tile_mmio(xe), &ep); if (ep.cookie != XE_I2C_EP_COOKIE_DEVICE) return 0; -- cgit v1.2.3 From f6c23e4589bdc69a5d2f79aed5c5bddd5d406cbe Mon Sep 17 00:00:00 2001 From: Ashutosh Dixit Date: Mon, 29 Jun 2026 10:26:34 -0700 Subject: drm/xe/oa: Fix offset alignment for MERT WHITELIST_OA_MERT_MMIO_TRG 'head' argument for WHITELIST_OA_MERT_MMIO_TRG was previously wrong (not multiple of 16). Fix this. Fixes: ec02e49f21bc ("drm/xe/rtp: Whitelist OAMERT MMIO trigger registers") Cc: stable@vger.kernel.org Reviewed-by: Umesh Nerlige Ramappa Signed-off-by: Ashutosh Dixit Link: https://patch.msgid.link/20260629172634.1100983-1-ashutosh.dixit@intel.com --- drivers/gpu/drm/xe/xe_reg_whitelist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.c b/drivers/gpu/drm/xe/xe_reg_whitelist.c index fe996d23007b..cab1b578ca0e 100644 --- a/drivers/gpu/drm/xe/xe_reg_whitelist.c +++ b/drivers/gpu/drm/xe/xe_reg_whitelist.c @@ -132,7 +132,7 @@ static const struct xe_rtp_table_sr oa_whitelist = XE_RTP_TABLE_SR( OAM_HEAD_POINTER(XE_OAM_SCMI_1_BASE_ADJ)) #define WHITELIST_OA_MERT_MMIO_TRG \ - WHITELIST_OA_MMIO_TRG(OAMERT_MMIO_TRG, OAMERT_STATUS, OAMERT_HEAD_POINTER) + WHITELIST_OA_MMIO_TRG(OAMERT_MMIO_TRG, OAMERT_STATUS, OAMERT_TAIL_POINTER) { XE_RTP_NAME("oag_mmio_trg_rcs"), XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, XE_RTP_END_VERSION_UNDEFINED), -- cgit v1.2.3 From 13b9555ffb0304d736fcad01e7a75d329b81ae9a Mon Sep 17 00:00:00 2001 From: Riana Tauro Date: Mon, 29 Jun 2026 13:58:03 +0530 Subject: drm/xe/xe_pci_error: Implement PCI error recovery callbacks Add error_detected, mmio_enabled, slot_reset and resume recovery callbacks to handle PCIe Advanced Error Reporting (AER) errors. For fatal errors, the device is wedged and becomes inaccessible. Return PCI_ERS_RESULT_NEED_RESET from error_detected to request a Secondary Bus Reset (SBR). For non-fatal errors, return PCI_ERS_RESULT_CAN_RECOVER from error_detected to trigger the mmio_enabled callback. In this callback, the device is queried to determine the error cause and attempt recovery based on the error type. Once the secondary bus reset(SBR) is completed the slot_reset callback cleanly removes and reprobe the device to restore functionality. Cc: Matthew Brost Cc: Matt Roper Reviewed-by: Mallesh Koujalagi Link: https://patch.msgid.link/20260629082802.3690896-7-riana.tauro@intel.com Signed-off-by: Riana Tauro --- drivers/gpu/drm/xe/Makefile | 1 + drivers/gpu/drm/xe/xe_pci.c | 2 + drivers/gpu/drm/xe/xe_pci_error.c | 118 ++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/xe/xe_pci_error.h | 13 +++++ 4 files changed, 134 insertions(+) create mode 100644 drivers/gpu/drm/xe/xe_pci_error.c create mode 100644 drivers/gpu/drm/xe/xe_pci_error.h diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 8e7b146880f4..3c001b2a4aec 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -101,6 +101,7 @@ xe-y += xe_bb.o \ xe_page_reclaim.o \ xe_pat.o \ xe_pci.o \ + xe_pci_error.o \ xe_pci_rebar.o \ xe_pcode.o \ xe_pm.o \ diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index 03362480e3e0..c194c19dac32 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -26,6 +26,7 @@ #include "xe_guc.h" #include "xe_mmio.h" #include "xe_module.h" +#include "xe_pci_error.h" #include "xe_pci_rebar.h" #include "xe_pci_sriov.h" #include "xe_pci_types.h" @@ -1350,6 +1351,7 @@ static struct pci_driver xe_pci_driver = { .remove = xe_pci_remove, .shutdown = xe_pci_shutdown, .sriov_configure = xe_pci_sriov_configure, + .err_handler = &xe_pci_error_handlers, #ifdef CONFIG_PM_SLEEP .driver.pm = &xe_pm_ops, #endif diff --git a/drivers/gpu/drm/xe/xe_pci_error.c b/drivers/gpu/drm/xe/xe_pci_error.c new file mode 100644 index 000000000000..10424d038e79 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_pci_error.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2026 Intel Corporation + */ + +#include + +#include "xe_device.h" +#include "xe_gt.h" +#include "xe_pci.h" +#include "xe_pm.h" +#include "xe_printk.h" +#include "xe_survivability_mode.h" + +static void prepare_device_for_reset(struct pci_dev *pdev) +{ + struct xe_device *xe = pdev_to_xe_device(pdev); + struct xe_gt *gt; + u8 id; + + /* + * Wedge the device to prevent userspace access but do not send the uevent. + * xe_device_wedged_fini() releases runtime pm if wedged flag is set, so acquire a runtime + * pm reference to avoid underflow. + */ + if (!atomic_xchg(&xe->wedged.flag, 1)) + xe_pm_runtime_get_noresume(xe); + + for_each_gt(gt, xe, id) + xe_gt_declare_wedged(gt); + + pci_disable_device(pdev); +} + +static pci_ers_result_t xe_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) +{ + struct xe_device *xe = pdev_to_xe_device(pdev); + + xe_info(xe, "PCI error: detected state = %d\n", state); + + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + + /* If the device is already wedged or in survivability mode, do not attempt recovery */ + if (xe_survivability_mode_is_boot_enabled(xe) || xe_device_wedged(xe)) + return PCI_ERS_RESULT_DISCONNECT; + + switch (state) { + case pci_channel_io_normal: + return PCI_ERS_RESULT_CAN_RECOVER; + case pci_channel_io_frozen: + prepare_device_for_reset(pdev); + return PCI_ERS_RESULT_NEED_RESET; + default: + xe_info(xe, "PCI error: unknown state %d\n", state); + return PCI_ERS_RESULT_DISCONNECT; + } +} + +static pci_ers_result_t xe_pci_error_mmio_enabled(struct pci_dev *pdev) +{ + struct xe_device *xe = pdev_to_xe_device(pdev); + + xe_info(xe, "PCI error: MMIO enabled\n"); + + /* TODO: Query system controller for the type of error and take appropriate action */ + return PCI_ERS_RESULT_RECOVERED; +} + +static pci_ers_result_t xe_pci_error_slot_reset(struct pci_dev *pdev) +{ + const struct pci_device_id *ent = pci_match_id(pdev->driver->id_table, pdev); + struct xe_device *xe = pdev_to_xe_device(pdev); + + xe_info(xe, "PCI error: slot reset\n"); + + pci_restore_state(pdev); + + if (pci_enable_device(pdev)) { + xe_err(xe, "Cannot re-enable PCI device after reset\n"); + return PCI_ERS_RESULT_DISCONNECT; + } + + /* + * Secondary Bus Reset causes all VRAM state to be lost along with + * hardware state. As an initial step, re-probe the device to + * re-initialize the driver and hardware. + * TODO: optimize by re-initializing only the hardware state and re-creating + * kernel BOs. + */ + pdev->driver->remove(pdev); + + if (pdev->driver->probe(pdev, ent)) + return PCI_ERS_RESULT_DISCONNECT; + + xe = pdev_to_xe_device(pdev); + + /* Wedge the device to prevent I/O operations till the resume callback */ + atomic_set(&xe->wedged.flag, 1); + + return PCI_ERS_RESULT_RECOVERED; +} + +static void xe_pci_error_resume(struct pci_dev *pdev) +{ + struct xe_device *xe = pdev_to_xe_device(pdev); + + xe_info(xe, "PCI error: resume\n"); + + atomic_set(&xe->wedged.flag, 0); +} + +const struct pci_error_handlers xe_pci_error_handlers = { + .error_detected = xe_pci_error_detected, + .mmio_enabled = xe_pci_error_mmio_enabled, + .slot_reset = xe_pci_error_slot_reset, + .resume = xe_pci_error_resume, +}; diff --git a/drivers/gpu/drm/xe/xe_pci_error.h b/drivers/gpu/drm/xe/xe_pci_error.h new file mode 100644 index 000000000000..725ad0214e62 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_pci_error.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2026 Intel Corporation + */ + +#ifndef _XE_PCI_ERROR_H_ +#define _XE_PCI_ERROR_H_ + +struct pci_error_handlers; + +extern const struct pci_error_handlers xe_pci_error_handlers; + +#endif -- cgit v1.2.3 From 0a0fae3327a537b23e86463240e7381ddb5e31a1 Mon Sep 17 00:00:00 2001 From: Riana Tauro Date: Mon, 29 Jun 2026 13:58:04 +0530 Subject: drm/xe/xe_pci_error: Group all devres to release them on PCIe slot reset Add devres grouping to handle device resource cleanup during PCI error recovery. Secondary Bus Reset (SBR) is triggered by PCI core when the error_detected/mmio_enabled callbacks return PCI_ERS_RESULT_NEED_RESET. Once SBR is complete, the slot_reset callback is triggered. SBR wipes out all device memory requiring XE KMD to perform a device removal and reprobe. Calling xe_pci_remove() alone does not free the devres allocated. Since there are no exported functions to release all devres, group the devres allocations and release the entire group during slot reset to ensure proper cleanup. Cc: Matthew Brost Cc: Himal Prasad Ghimiray Reviewed-by: Mallesh Koujalagi Link: https://patch.msgid.link/20260629082802.3690896-8-riana.tauro@intel.com Signed-off-by: Riana Tauro --- drivers/gpu/drm/xe/xe_device_types.h | 3 +++ drivers/gpu/drm/xe/xe_pci.c | 8 ++++++++ drivers/gpu/drm/xe/xe_pci_error.c | 1 + 3 files changed, 12 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index 46a9e9fad7a9..9d42edba374b 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -495,6 +495,9 @@ struct xe_device { bool inconsistent_reset; } wedged; + /** @devres_group: devres group */ + void *devres_group; + /** @bo_device: Struct to control async free of BOs */ struct xe_bo_dev { /** @bo_device.async_free: Free worker */ diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index c194c19dac32..096c99b865b4 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -1078,6 +1078,7 @@ static int xe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) const struct xe_device_desc *desc = (const void *)ent->driver_data; const struct xe_subplatform_desc *subplatform_desc; struct xe_device *xe; + void *group; int err; subplatform_desc = find_subplatform(desc, pdev->device); @@ -1105,6 +1106,11 @@ static int xe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (xe_display_driver_probe_defer(pdev)) return -EPROBE_DEFER; + /* Group all devres so xe_pci_error_slot_reset() can release them as a unit. */ + group = devres_open_group(&pdev->dev, NULL, GFP_KERNEL); + if (!group) + return -ENOMEM; + err = pcim_enable_device(pdev); if (err) return err; @@ -1113,6 +1119,8 @@ static int xe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (IS_ERR(xe)) return PTR_ERR(xe); + xe->devres_group = group; + pci_set_drvdata(pdev, &xe->drm); xe_pm_assert_unbounded_bridge(xe); diff --git a/drivers/gpu/drm/xe/xe_pci_error.c b/drivers/gpu/drm/xe/xe_pci_error.c index 10424d038e79..2f7316266333 100644 --- a/drivers/gpu/drm/xe/xe_pci_error.c +++ b/drivers/gpu/drm/xe/xe_pci_error.c @@ -89,6 +89,7 @@ static pci_ers_result_t xe_pci_error_slot_reset(struct pci_dev *pdev) * kernel BOs. */ pdev->driver->remove(pdev); + devres_release_group(&pdev->dev, xe->devres_group); if (pdev->driver->probe(pdev, ent)) return PCI_ERS_RESULT_DISCONNECT; -- cgit v1.2.3 From e46ee82f120f7f6ac4a2bf8ee6199ef65ceaea1a Mon Sep 17 00:00:00 2001 From: Riana Tauro Date: Mon, 29 Jun 2026 13:58:05 +0530 Subject: drm/xe: Skip device access during PCI error recovery When a fatal error occurs and the error_detected callback is invoked the device is inaccessible. The error_detected callback wedges the device causing the jobs to timeout. The timedout handler acquires forcewake to dump devcoredump and triggers a GT reset. Since the device is inaccessible this causes errors. Skip all mmio accesses and gt reset when the device is in reset. Cc: Matthew Brost Cc: Himal Prasad Ghimiray Reviewed-by: Mallesh Koujalagi Link: https://patch.msgid.link/20260629082802.3690896-9-riana.tauro@intel.com Signed-off-by: Riana Tauro --- drivers/gpu/drm/xe/xe_device.h | 15 +++++++++++++++ drivers/gpu/drm/xe/xe_device_types.h | 3 +++ drivers/gpu/drm/xe/xe_gt.c | 14 ++++++++++---- drivers/gpu/drm/xe/xe_guc_submit.c | 9 +++++---- drivers/gpu/drm/xe/xe_pci_error.c | 3 +++ 5 files changed, 36 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_device.h b/drivers/gpu/drm/xe/xe_device.h index 8056d8bd7d6d..a03760d0ce38 100644 --- a/drivers/gpu/drm/xe/xe_device.h +++ b/drivers/gpu/drm/xe/xe_device.h @@ -181,6 +181,21 @@ static inline bool xe_device_has_mert(const struct xe_device *xe) return xe->info.has_mert; } +static inline bool xe_device_is_in_reset(struct xe_device *xe) +{ + return atomic_read(&xe->in_reset); +} + +static inline void xe_device_set_in_reset(struct xe_device *xe) +{ + atomic_set(&xe->in_reset, 1); +} + +static inline void xe_device_clear_in_reset(struct xe_device *xe) +{ + atomic_set(&xe->in_reset, 0); +} + u32 xe_device_ccs_bytes(struct xe_device *xe, u64 size); void xe_device_snapshot_print(struct xe_device *xe, struct drm_printer *p); diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index 9d42edba374b..022e08205897 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -483,6 +483,9 @@ struct xe_device { /** @needs_flr_on_fini: requests function-reset on fini */ bool needs_flr_on_fini; + /** @in_reset: Indicates if device is in reset */ + atomic_t in_reset; + /** @wedged: Struct to control Wedged States and mode */ struct { /** @wedged.flag: Xe device faced a critical error and is now blocked. */ diff --git a/drivers/gpu/drm/xe/xe_gt.c b/drivers/gpu/drm/xe/xe_gt.c index 783eb6d631b5..d904527a8898 100644 --- a/drivers/gpu/drm/xe/xe_gt.c +++ b/drivers/gpu/drm/xe/xe_gt.c @@ -917,6 +917,9 @@ static void gt_reset_worker(struct work_struct *w) if (xe_device_wedged(gt_to_xe(gt))) goto err_pm_put; + if (xe_device_is_in_reset(gt_to_xe(gt))) + goto err_pm_put; + /* We only support GT resets with GuC submission */ if (!xe_device_uc_enabled(gt_to_xe(gt))) goto err_pm_put; @@ -977,18 +980,21 @@ err_pm_put: void xe_gt_reset_async(struct xe_gt *gt) { - xe_gt_info(gt, "trying reset from %ps\n", __builtin_return_address(0)); + struct xe_device *xe = gt_to_xe(gt); + + if (xe_device_is_in_reset(xe)) + return; /* Don't do a reset while one is already in flight */ if (!xe_fault_inject_gt_reset() && xe_uc_reset_prepare(>->uc)) return; - xe_gt_info(gt, "reset queued\n"); + xe_gt_info(gt, "reset queued from %ps\n", __builtin_return_address(0)); /* Pair with put in gt_reset_worker() if work is enqueued */ - xe_pm_runtime_get_noresume(gt_to_xe(gt)); + xe_pm_runtime_get_noresume(xe); if (!queue_work(gt->ordered_wq, >->reset.worker)) - xe_pm_runtime_put(gt_to_xe(gt)); + xe_pm_runtime_put(xe); } void xe_gt_suspend_prepare(struct xe_gt *gt) diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index 9458bf477fa6..12416bfa3255 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -1532,7 +1532,7 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) * If devcoredump not captured and GuC capture for the job is not ready * do manual capture first and decide later if we need to use it */ - if (!exec_queue_killed(q) && !xe->devcoredump.captured && + if (!xe_device_is_in_reset(xe) && !exec_queue_killed(q) && !xe->devcoredump.captured && !xe_guc_capture_get_matching_and_lock(q)) { /* take force wake before engine register manual capture */ CLASS(xe_force_wake, fw_ref)(gt_to_fw(q->gt), XE_FORCEWAKE_ALL); @@ -1554,8 +1554,8 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) set_exec_queue_banned(q); /* Kick job / queue off hardware */ - if (!wedged && (exec_queue_enabled(primary) || - exec_queue_pending_disable(primary))) { + if (!xe_device_is_in_reset(xe) && !wedged && + (exec_queue_enabled(primary) || exec_queue_pending_disable(primary))) { int ret; if (exec_queue_reset(primary)) @@ -1623,7 +1623,8 @@ trigger_reset: trace_xe_sched_job_timedout(job); - if (!exec_queue_killed(q)) + /* Do not access device if in reset */ + if (!xe_device_is_in_reset(xe) && !exec_queue_killed(q)) xe_devcoredump(q, job, "Timedout job - seqno=%u, lrc_seqno=%u, guc_id=%d, flags=0x%lx", xe_sched_job_seqno(job), xe_sched_job_lrc_seqno(job), diff --git a/drivers/gpu/drm/xe/xe_pci_error.c b/drivers/gpu/drm/xe/xe_pci_error.c index 2f7316266333..9b78cc0d3293 100644 --- a/drivers/gpu/drm/xe/xe_pci_error.c +++ b/drivers/gpu/drm/xe/xe_pci_error.c @@ -26,6 +26,8 @@ static void prepare_device_for_reset(struct pci_dev *pdev) if (!atomic_xchg(&xe->wedged.flag, 1)) xe_pm_runtime_get_noresume(xe); + xe_device_set_in_reset(xe); + for_each_gt(gt, xe, id) xe_gt_declare_wedged(gt); @@ -88,6 +90,7 @@ static pci_ers_result_t xe_pci_error_slot_reset(struct pci_dev *pdev) * TODO: optimize by re-initializing only the hardware state and re-creating * kernel BOs. */ + xe_device_clear_in_reset(xe); pdev->driver->remove(pdev); devres_release_group(&pdev->dev, xe->devres_group); -- cgit v1.2.3 From 7d8c458854814bf9e9aa4bc217662fd01a86d0f6 Mon Sep 17 00:00:00 2001 From: Riana Tauro Date: Mon, 29 Jun 2026 13:58:06 +0530 Subject: drm/xe/xe_ras: Initialize Uncorrectable AER Registers Uncorrectable errors from different endpoints in the device are steered to the USP(Upstream Switch Port) which is a PCI Advanced Error Reporting (AER) Compliant device. Downgrade all the errors to non-fatal to prevent PCIe bus driver from triggering a Secondary Bus Reset (SBR). This allows error detection, containment and recovery in the driver. The Uncorrectable Error Severity Register has the 'Uncorrectable Internal Error Severity' set to fatal by default. Set this to non-fatal and unmask the error. Reviewed-by: Mallesh Koujalagi Link: https://patch.msgid.link/20260629082802.3690896-10-riana.tauro@intel.com Signed-off-by: Riana Tauro --- drivers/gpu/drm/xe/xe_ras.c | 70 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_ras.c b/drivers/gpu/drm/xe/xe_ras.c index 44f4e1a3455b..74d5016d9ffe 100644 --- a/drivers/gpu/drm/xe/xe_ras.c +++ b/drivers/gpu/drm/xe/xe_ras.c @@ -131,6 +131,68 @@ static inline const char *comp_to_str(u8 component) return xe_ras_components[component]; } +static struct pci_dev *find_usp_dev(struct pci_dev *pdev) +{ + struct pci_dev *vsp; + + /* + * Device Hierarchy: + * + * Upstream Switch Port (USP) --> Virtual Switch Port (VSP) --> SGunit (GPU endpoint) + */ + vsp = pci_upstream_bridge(pdev); + if (!vsp) + return NULL; + + return pci_upstream_bridge(vsp); +} + +static void ras_usp_aer_init(struct xe_device *xe) +{ + struct pci_dev *pdev = to_pci_dev(xe->drm.dev); + struct pci_dev *usp; + u16 aer_cap; + u32 status; + + usp = find_usp_dev(pdev); + if (!usp) + return; + + aer_cap = pci_find_ext_capability(usp, PCI_EXT_CAP_ID_ERR); + if (!aer_cap) { + dev_warn(&usp->dev, "AER capability unavailable\n"); + return; + } + + /* + * Clear any stale Uncorrectable Internal Error Status event in Uncorrectable Error + * Status Register. + */ + pci_read_config_dword(usp, aer_cap + PCI_ERR_UNCOR_STATUS, &status); + if (status & PCI_ERR_UNC_INTN) + pci_write_config_dword(usp, aer_cap + PCI_ERR_UNCOR_STATUS, PCI_ERR_UNC_INTN); + + /* + * All errors are steered to USP which is a PCIe AER Compliant device. + * Downgrade all the errors to non-fatal to prevent PCIe bus driver + * from triggering a Secondary Bus Reset (SBR). This allows error + * detection, containment and recovery in the driver. + * + * The Uncorrectable Error Severity Register has the 'Uncorrectable + * Internal Error Severity' set to fatal by default. Set this to + * non-fatal and unmask the error. + */ + + /* Downgrade Uncorrectable Internal Error to non-fatal */ + pci_clear_and_set_config_dword(usp, aer_cap + PCI_ERR_UNCOR_SEVER, PCI_ERR_UNC_INTN, 0); + + /* Unmask Uncorrectable Internal Error */ + pci_clear_and_set_config_dword(usp, aer_cap + PCI_ERR_UNCOR_MASK, PCI_ERR_UNC_INTN, 0); + + pci_save_state(usp); + dev_dbg(&usp->dev, "Uncorrectable Internal Errors downgraded and unmasked\n"); +} + void xe_ras_counter_threshold_crossed(struct xe_device *xe, struct xe_sysctrl_event_response *response) { @@ -274,7 +336,7 @@ int xe_ras_clear_counter(struct xe_device *xe, u8 severity, u8 component) * xe_ras_init - Initialize Xe RAS * @xe: xe device instance * - * Register drm_ras nodes + * Initialize Xe RAS */ void xe_ras_init(struct xe_device *xe) { @@ -282,4 +344,10 @@ void xe_ras_init(struct xe_device *xe) return; xe_drm_ras_init(xe); + + if (!xe->info.has_sysctrl) + return; + + if (IS_ENABLED(CONFIG_PCIEAER)) + ras_usp_aer_init(xe); } -- cgit v1.2.3 From e6f2d0b757c4fb577a513c577140109d1d292a9a Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Wed, 1 Jul 2026 18:24:34 -0700 Subject: drm/xe: Fix PTE index in xe_vm_populate_pgtable() for chunked binds xe_vm_populate_pgtable() indexed the source PTE array (update->pt_entries) by the per-call loop counter, assuming each call starts at the first entry of the update. That holds for the CPU bind path (xe_migrate_update_pgtables_cpu), which populates a whole update in a single call, but not for the GPU bind path: write_pgtable() splits an update into MAX_PTE_PER_SDI (510) sized MI_STORE_DATA_IMM chunks, invoking the populate callback once per chunk with an advancing qword_ofs but a fresh command- buffer destination pointer. As a result, every chunk after the first re-read pt_entries from index 0 instead of from its true offset, so PTEs beyond the first 510 entries of a single update were programmed with the wrong physical pages, shifting the mapping by exactly MAX_PTE_PER_SDI pages. This stayed latent because a single update only exceeds 510 qwords when a large (e.g. 2M) region is bound as individual 4K PTEs rather than a single huge-page entry, which happens when the backing store is sufficiently fragmented. It was surfaced by the BO defrag path, which deliberately rebinds such fragmented ranges via the GPU bind path, producing deterministic data corruption offset by 510 pages. Index pt_entries by the chunk's absolute offset relative to update->ofs so both the CPU and GPU paths pick the correct entries. Fixes: dd08ebf6c352 ("drm/xe: Introduce a new DRM driver for Intel GPUs") Cc: stable@vger.kernel.org Assisted-by: GitHub_Copilot:claude-opus-4.8 Signed-off-by: Matthew Brost Reviewed-by: Matthew Auld Link: https://patch.msgid.link/20260702012434.3861171-1-matthew.brost@intel.com --- drivers/gpu/drm/xe/xe_pt.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c index 5e82fc28edfc..5fdad444009f 100644 --- a/drivers/gpu/drm/xe/xe_pt.c +++ b/drivers/gpu/drm/xe/xe_pt.c @@ -1026,12 +1026,22 @@ xe_vm_populate_pgtable(struct xe_migrate_pt_update *pt_update, struct xe_tile *t u64 *ptr = data; u32 i; + /* + * @qword_ofs is the absolute entry offset within the page table, while + * @ptes is indexed relative to @update->ofs (its first entry). The GPU + * path (write_pgtable) splits a single update into MAX_PTE_PER_SDI-sized + * chunks, calling this with an advancing @qword_ofs but a fresh @data + * pointer per chunk, so translate back into a @ptes index rather than + * assuming the chunk starts at ptes[0]. + */ for (i = 0; i < num_qwords; i++) { + u32 idx = qword_ofs - update->ofs + i; + if (map) xe_map_wr(tile_to_xe(tile), map, (qword_ofs + i) * - sizeof(u64), u64, ptes[i].pte); + sizeof(u64), u64, ptes[idx].pte); else - ptr[i] = ptes[i].pte; + ptr[i] = ptes[idx].pte; } } -- cgit v1.2.3 From 1b63a25d5dc851c20a676020e0956ee027aee410 Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Tue, 9 Jun 2026 17:17:33 -0300 Subject: drm/xe: Add framework for info probing Functions xe_info_init_early() and xe_info_init() currently probe some information from the hardware while doing initialization of info fields. Besides mixing responsibilities, another issue from this approach is that kunit tests need to implement static stubs for the probing part. Let's prepare the ground to ensuring that those functions stop probing the information from the hardware by creating the necessary framework for extracting the probing bits out of them. Do that by creating a new struct type called xe_probed_info and the functions responsible for populating it. In upcoming changes, we will gradually refactor the code so that all info needed by xe_info_init_early() and xe_info_init() that is probed from the hardware is passed to them via struct xe_probed_info. Reviewed-by: Dnyaneshwar Bhadane Reviewed-by: Violet Monti Link: https://patch.msgid.link/20260609-xe-probe-info-v1-1-21e83e188e60@intel.com Signed-off-by: Gustavo Sousa --- drivers/gpu/drm/xe/tests/xe_pci.c | 16 +++++++++++++-- drivers/gpu/drm/xe/xe_pci.c | 41 +++++++++++++++++++++++++++++++++++---- 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/xe/tests/xe_pci.c b/drivers/gpu/drm/xe/tests/xe_pci.c index 9240aff779da..51d032a9e01a 100644 --- a/drivers/gpu/drm/xe/tests/xe_pci.c +++ b/drivers/gpu/drm/xe/tests/xe_pci.c @@ -338,13 +338,21 @@ static void fake_xe_info_probe_tile_count(struct xe_device *xe) /* Nothing to do, just use the statically defined value. */ } +static int fake_probe_info(struct xe_device *xe, + struct xe_probed_info *probed_info) +{ + return 0; +} + int xe_pci_fake_device_init(struct xe_device *xe) { struct kunit *test = kunit_get_current_test(); struct xe_pci_fake_data *data = test->priv; + struct xe_probed_info probed_info = {}; const struct pci_device_id *ent = pciidlist; const struct xe_device_desc *desc; const struct xe_subplatform_desc *subplatform_desc; + int err; if (!data) { desc = (const void *)ent->driver_data; @@ -379,8 +387,12 @@ done: kunit_activate_static_stub(test, xe_info_probe_tile_count, fake_xe_info_probe_tile_count); - xe_info_init_early(xe, desc, subplatform_desc); - xe_info_init(xe, desc); + err = fake_probe_info(xe, &probed_info); + if (err) + return err; + + xe_info_init_early(xe, desc, subplatform_desc, &probed_info); + xe_info_init(xe, desc, &probed_info); return 0; } diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index 096c99b865b4..6156d8689430 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -739,13 +739,27 @@ static void init_devid(struct xe_device *xe) xe->info.revid = pdev->revision; } +struct xe_probed_info { + /* Nothing for now. */ +}; + +/* + * Probe from the hardware the info required by xe_info_init_early(). + */ +static int xe_probe_info_early(struct xe_device *xe, + struct xe_probed_info *probed_info) +{ + return 0; +} + /* * Initialize device info content that only depends on static driver_data * passed to the driver at probe time from PCI ID table. */ static int xe_info_init_early(struct xe_device *xe, const struct xe_device_desc *desc, - const struct xe_subplatform_desc *subplatform_desc) + const struct xe_subplatform_desc *subplatform_desc, + struct xe_probed_info *probed_info) { int err; @@ -912,6 +926,15 @@ static struct xe_gt *alloc_media_gt(struct xe_tile *tile, return gt; } +/* + * Probe from the hardware the info required by xe_info_init(). + */ +static int xe_probe_info(struct xe_device *xe, + struct xe_probed_info *probed_info) +{ + return 0; +} + /* * Initialize device info content that does require knowledge about * graphics / media IP version. @@ -919,7 +942,8 @@ static struct xe_gt *alloc_media_gt(struct xe_tile *tile, * present in device info. */ static int xe_info_init(struct xe_device *xe, - const struct xe_device_desc *desc) + const struct xe_device_desc *desc, + struct xe_probed_info *probed_info) { u32 graphics_gmdid_revid = 0, media_gmdid_revid = 0; const struct xe_ip *graphics_ip; @@ -1075,6 +1099,7 @@ static void xe_pci_remove(struct pci_dev *pdev) */ static int xe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { + struct xe_probed_info probed_info = {}; const struct xe_device_desc *desc = (const void *)ent->driver_data; const struct xe_subplatform_desc *subplatform_desc; struct xe_device *xe; @@ -1127,7 +1152,11 @@ static int xe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); - err = xe_info_init_early(xe, desc, subplatform_desc); + err = xe_probe_info_early(xe, &probed_info); + if (err) + return err; + + err = xe_info_init_early(xe, desc, subplatform_desc, &probed_info); if (err) return err; @@ -1146,7 +1175,11 @@ static int xe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) return err; - err = xe_info_init(xe, desc); + err = xe_probe_info(xe, &probed_info); + if (err) + return err; + + err = xe_info_init(xe, desc, &probed_info); if (err) return err; -- cgit v1.2.3 From 246a005895ee75bf5260159f3414d2f072430ef1 Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Tue, 9 Jun 2026 17:17:34 -0300 Subject: drm/xe/step: Pass xe_step_info to xe_step_*_get() functions The xe_step_*_get() functions update the step directly in xe->info.step and are called by functions xe_info_init_early() and xe_info_init(). As the stepping info is something probed from the hardware (via PCI revid and/or GMDID) and we want to move away from probing inside xe_info_init*() functions, let's make xe_step_*_get() functions modify a pointer to the step structure instead of modifying xe->info.step directly: this will allow an upcoming change that will move those function calls out of the info init functions and will pass a member of struct xe_probed_info instead of xe->info.step. Reviewed-by: Dnyaneshwar Bhadane Reviewed-by: Violet Monti Link: https://patch.msgid.link/20260609-xe-probe-info-v1-2-21e83e188e60@intel.com Signed-off-by: Gustavo Sousa --- drivers/gpu/drm/xe/xe_pci.c | 6 +++--- drivers/gpu/drm/xe/xe_step.c | 33 ++++++++++++++++++++------------- drivers/gpu/drm/xe/xe_step.h | 7 ++++--- 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index 6156d8689430..c4f7ffd03987 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -813,7 +813,7 @@ static int xe_info_init_early(struct xe_device *xe, xe->info.max_gt_per_tile = desc->max_gt_per_tile; xe->info.tile_count = 1 + desc->max_remote_tiles; - xe_step_platform_get(xe); + xe_step_platform_get(xe, &xe->info.step); err = xe_tile_init_early(xe_device_get_root_tile(xe), xe, 0); if (err) @@ -965,7 +965,7 @@ static int xe_info_init(struct xe_device *xe, if (desc->pre_gmdid_graphics_ip) { graphics_ip = desc->pre_gmdid_graphics_ip; media_ip = desc->pre_gmdid_media_ip; - xe_step_pre_gmdid_get(xe); + xe_step_pre_gmdid_get(xe, &xe->info.step); } else { xe_assert(xe, !desc->pre_gmdid_media_ip); ret = handle_gmdid(xe, &graphics_ip, &media_ip, @@ -973,7 +973,7 @@ static int xe_info_init(struct xe_device *xe, if (ret) return ret; - xe_step_gmdid_get(xe, graphics_gmdid_revid, media_gmdid_revid); + xe_step_gmdid_get(xe, graphics_gmdid_revid, media_gmdid_revid, &xe->info.step); } /* diff --git a/drivers/gpu/drm/xe/xe_step.c b/drivers/gpu/drm/xe/xe_step.c index fb9c31613ca7..49dc64f2b363 100644 --- a/drivers/gpu/drm/xe/xe_step.c +++ b/drivers/gpu/drm/xe/xe_step.c @@ -111,11 +111,12 @@ __diag_pop(); /** * xe_step_platform_get - Determine platform-level stepping from PCI revid * @xe: Xe device + * @step: Pointer to the step struct to update * * Convert the PCI revid into a platform-level stepping value and store that - * in the device info. + * in @step->platform. */ -void xe_step_platform_get(struct xe_device *xe) +void xe_step_platform_get(struct xe_device *xe, struct xe_step_info *step) { /* * Not all platforms map PCI revid directly into our symbolic stepping @@ -127,17 +128,20 @@ void xe_step_platform_get(struct xe_device *xe) */ if (xe->info.platform == XE_NOVALAKE_P) - xe->info.step.platform = STEP_A0 + xe->info.revid; + step->platform = STEP_A0 + xe->info.revid; } /** * xe_step_pre_gmdid_get - Determine IP steppings from PCI revid * @xe: Xe device + * @step: Pointer to the step struct to update * - * Convert the PCI revid into proper IP steppings. This should only be - * used on platforms that do not have GMD_ID support. + * Convert the PCI revid into proper IP steppings and update @step->basedie, + * @step->graphics and @step->media accordingly. + * + * This should only be used on platforms that do not have GMD_ID support. */ -void xe_step_pre_gmdid_get(struct xe_device *xe) +void xe_step_pre_gmdid_get(struct xe_device *xe, struct xe_step_info *step) { const struct xe_step_info *revids = NULL; u16 revid = xe->info.revid; @@ -234,9 +238,9 @@ void xe_step_pre_gmdid_get(struct xe_device *xe) } done: - xe->info.step.graphics = graphics; - xe->info.step.media = media; - xe->info.step.basedie = basedie; + step->graphics = graphics; + step->media = media; + step->basedie = basedie; } /** @@ -244,8 +248,10 @@ done: * @xe: Xe device * @graphics_gmdid_revid: value of graphics GMD_ID register's revid field * @media_gmdid_revid: value of media GMD_ID register's revid field + * @step: Poninter to the step struct to update. * - * Convert the revid fields of the GMD_ID registers into proper IP steppings. + * Convert the revid fields of the GMD_ID registers into proper IP steppings + * and update @step->graphics and @step->media accordingly. * * GMD_ID revid values are currently expected to have consistent meanings on * all platforms: major steppings (A0, B0, etc.) are 4 apart, with minor @@ -253,7 +259,8 @@ done: */ void xe_step_gmdid_get(struct xe_device *xe, u32 graphics_gmdid_revid, - u32 media_gmdid_revid) + u32 media_gmdid_revid, + struct xe_step_info *step) { u8 graphics = STEP_A0 + graphics_gmdid_revid; u8 media = STEP_A0 + media_gmdid_revid; @@ -270,8 +277,8 @@ void xe_step_gmdid_get(struct xe_device *xe, media_gmdid_revid); } - xe->info.step.graphics = graphics; - xe->info.step.media = media; + step->graphics = graphics; + step->media = media; } #define STEP_NAME_CASE(name) \ diff --git a/drivers/gpu/drm/xe/xe_step.h b/drivers/gpu/drm/xe/xe_step.h index ea36b22cc297..c6cea95a3727 100644 --- a/drivers/gpu/drm/xe/xe_step.h +++ b/drivers/gpu/drm/xe/xe_step.h @@ -12,12 +12,13 @@ struct xe_device; -void xe_step_platform_get(struct xe_device *xe); +void xe_step_platform_get(struct xe_device *xe, struct xe_step_info *step); -void xe_step_pre_gmdid_get(struct xe_device *xe); +void xe_step_pre_gmdid_get(struct xe_device *xe, struct xe_step_info *step); void xe_step_gmdid_get(struct xe_device *xe, u32 graphics_gmdid_revid, - u32 media_gmdid_revid); + u32 media_gmdid_revid, + struct xe_step_info *step); static inline u32 xe_step_to_gmdid(enum intel_step step) { return step - STEP_A0; } const char *xe_step_name(enum intel_step step); -- cgit v1.2.3 From 70b85cb2b590da3325310f0bb50bbe3312f18687 Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Tue, 9 Jun 2026 17:17:35 -0300 Subject: drm/xe: Add devid and revid to xe_probed_info The PCI devid and revid fields are info that we probe from the hardware (indirectly via the PCI subsystem). Add them to xe_probed_info and set them via xe_probe_info_early(), since the respective fields in xe->info are updated in xe_info_init_early(). Reviewed-by: Dnyaneshwar Bhadane Reviewed-by: Violet Monti Link: https://patch.msgid.link/20260609-xe-probe-info-v1-3-21e83e188e60@intel.com Signed-off-by: Gustavo Sousa --- drivers/gpu/drm/xe/tests/xe_pci.c | 6 ------ drivers/gpu/drm/xe/xe_pci.c | 23 ++++++++++------------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/xe/tests/xe_pci.c b/drivers/gpu/drm/xe/tests/xe_pci.c index 51d032a9e01a..1baf3cd0d381 100644 --- a/drivers/gpu/drm/xe/tests/xe_pci.c +++ b/drivers/gpu/drm/xe/tests/xe_pci.c @@ -311,11 +311,6 @@ 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) { @@ -382,7 +377,6 @@ 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/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index c4f7ffd03987..c767cf00607d 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -729,18 +729,9 @@ 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; -} - struct xe_probed_info { - /* Nothing for now. */ + u16 devid; + u8 revid; }; /* @@ -749,6 +740,11 @@ struct xe_probed_info { static int xe_probe_info_early(struct xe_device *xe, struct xe_probed_info *probed_info) { + struct pci_dev *pdev = to_pci_dev(xe->drm.dev); + + probed_info->devid = pdev->device; + probed_info->revid = pdev->revision; + return 0; } @@ -763,13 +759,14 @@ static int xe_info_init_early(struct xe_device *xe, { int err; + xe->info.devid = probed_info->devid; + xe->info.revid = probed_info->revid; + xe->info.platform_name = desc->platform_name; xe->info.platform = desc->platform; 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; -- cgit v1.2.3 From 15f280a7bac9c8cdec71af20fbec54a775466825 Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Tue, 9 Jun 2026 17:17:36 -0300 Subject: drm/xe/step: Make xe_step_platform_get() independent from xe->info Currently xe_step_platform_get() uses info fields from xe->info to define the platform-level stepping value. Because the platform-level stepping info depends on the PCI revid, it should be defined as part of xe_probe_info_early() instead of being directly probed inside xe_info_init_early(). Let's make sure that xe_step_platform_get() receives the necessary data as parameters and does not depend on xe->info. That will allow us to move the call up to xe_probe_info_early() in an upcoming change. Reviewed-by: Violet Monti Link: https://patch.msgid.link/20260609-xe-probe-info-v1-4-21e83e188e60@intel.com Signed-off-by: Gustavo Sousa --- drivers/gpu/drm/xe/xe_pci.c | 2 +- drivers/gpu/drm/xe/xe_step.c | 9 +++++---- drivers/gpu/drm/xe/xe_step.h | 3 ++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index c767cf00607d..5d97a9ed044c 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -810,7 +810,7 @@ static int xe_info_init_early(struct xe_device *xe, xe->info.max_gt_per_tile = desc->max_gt_per_tile; xe->info.tile_count = 1 + desc->max_remote_tiles; - xe_step_platform_get(xe, &xe->info.step); + xe_step_platform_get(xe->info.platform, xe->info.revid, &xe->info.step); err = xe_tile_init_early(xe_device_get_root_tile(xe), xe, 0); if (err) diff --git a/drivers/gpu/drm/xe/xe_step.c b/drivers/gpu/drm/xe/xe_step.c index 49dc64f2b363..55c1996f689e 100644 --- a/drivers/gpu/drm/xe/xe_step.c +++ b/drivers/gpu/drm/xe/xe_step.c @@ -110,13 +110,14 @@ __diag_pop(); /** * xe_step_platform_get - Determine platform-level stepping from PCI revid - * @xe: Xe device + * @platform: The Xe platform + * @revid: The PCI revid * @step: Pointer to the step struct to update * * Convert the PCI revid into a platform-level stepping value and store that * in @step->platform. */ -void xe_step_platform_get(struct xe_device *xe, struct xe_step_info *step) +void xe_step_platform_get(enum xe_platform platform, u8 revid, struct xe_step_info *step) { /* * Not all platforms map PCI revid directly into our symbolic stepping @@ -127,8 +128,8 @@ void xe_step_platform_get(struct xe_device *xe, struct xe_step_info *step) * checks. */ - if (xe->info.platform == XE_NOVALAKE_P) - step->platform = STEP_A0 + xe->info.revid; + if (platform == XE_NOVALAKE_P) + step->platform = STEP_A0 + revid; } /** diff --git a/drivers/gpu/drm/xe/xe_step.h b/drivers/gpu/drm/xe/xe_step.h index c6cea95a3727..5a5845335740 100644 --- a/drivers/gpu/drm/xe/xe_step.h +++ b/drivers/gpu/drm/xe/xe_step.h @@ -10,9 +10,10 @@ #include "xe_step_types.h" +enum xe_platform; struct xe_device; -void xe_step_platform_get(struct xe_device *xe, struct xe_step_info *step); +void xe_step_platform_get(enum xe_platform platform, u8 revid, struct xe_step_info *step); void xe_step_pre_gmdid_get(struct xe_device *xe, struct xe_step_info *step); void xe_step_gmdid_get(struct xe_device *xe, -- cgit v1.2.3 From b53155bd0e789647ba179f86ff29edf84ce7880d Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Tue, 9 Jun 2026 17:17:37 -0300 Subject: drm/xe: Add platform-level step info to xe_probed_info The platform-level step information depends on the PCI revid and, as such, should be probed in xe_probe_info_early() instead of xe_info_init_early(). Move the code accordingly. Note that we currently only update probed_info->step.platform as part of this change. We will deal with the other fields of probed_info->step as a follow-up change, which will be tied to the probing of graphics and media IPs. Reviewed-by: Dnyaneshwar Bhadane Reviewed-by: Violet Monti Link: https://patch.msgid.link/20260609-xe-probe-info-v1-5-21e83e188e60@intel.com Signed-off-by: Gustavo Sousa --- drivers/gpu/drm/xe/xe_pci.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index 5d97a9ed044c..fa43853eb591 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -732,12 +732,14 @@ static int handle_gmdid(struct xe_device *xe, struct xe_probed_info { u16 devid; u8 revid; + struct xe_step_info step; }; /* * Probe from the hardware the info required by xe_info_init_early(). */ static int xe_probe_info_early(struct xe_device *xe, + const struct xe_device_desc *desc, struct xe_probed_info *probed_info) { struct pci_dev *pdev = to_pci_dev(xe->drm.dev); @@ -745,6 +747,8 @@ static int xe_probe_info_early(struct xe_device *xe, probed_info->devid = pdev->device; probed_info->revid = pdev->revision; + xe_step_platform_get(desc->platform, probed_info->revid, &probed_info->step); + return 0; } @@ -761,6 +765,7 @@ static int xe_info_init_early(struct xe_device *xe, xe->info.devid = probed_info->devid; xe->info.revid = probed_info->revid; + xe->info.step.platform = probed_info->step.platform; xe->info.platform_name = desc->platform_name; xe->info.platform = desc->platform; @@ -810,8 +815,6 @@ static int xe_info_init_early(struct xe_device *xe, xe->info.max_gt_per_tile = desc->max_gt_per_tile; xe->info.tile_count = 1 + desc->max_remote_tiles; - xe_step_platform_get(xe->info.platform, xe->info.revid, &xe->info.step); - err = xe_tile_init_early(xe_device_get_root_tile(xe), xe, 0); if (err) return err; @@ -1149,7 +1152,7 @@ static int xe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); - err = xe_probe_info_early(xe, &probed_info); + err = xe_probe_info_early(xe, desc, &probed_info); if (err) return err; -- cgit v1.2.3 From 4a2cd8a48eaec34c30db1941a07204406b66db5e Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Tue, 9 Jun 2026 17:17:38 -0300 Subject: drm/xe/tests: Set non-GMDID graphics step in xe_pci_fake_device_init() Currently the logic to set the graphics step for non-GMDID-based platforms in kunit testing is defined in xe_wa_test_init(). That logic should rather belong to the helper xe_pci_fake_device_init(), so move it there. Reviewed-by: Dnyaneshwar Bhadane Reviewed-by: Violet Monti Link: https://patch.msgid.link/20260609-xe-probe-info-v1-6-21e83e188e60@intel.com Signed-off-by: Gustavo Sousa --- drivers/gpu/drm/xe/tests/xe_pci.c | 3 +++ drivers/gpu/drm/xe/tests/xe_wa_test.c | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/tests/xe_pci.c b/drivers/gpu/drm/xe/tests/xe_pci.c index 1baf3cd0d381..a665d5dbc472 100644 --- a/drivers/gpu/drm/xe/tests/xe_pci.c +++ b/drivers/gpu/drm/xe/tests/xe_pci.c @@ -388,6 +388,9 @@ done: xe_info_init_early(xe, desc, subplatform_desc, &probed_info); xe_info_init(xe, desc, &probed_info); + if (data && !data->graphics_verx100) + xe->info.step = data->step; + return 0; } EXPORT_SYMBOL_IF_KUNIT(xe_pci_fake_device_init); diff --git a/drivers/gpu/drm/xe/tests/xe_wa_test.c b/drivers/gpu/drm/xe/tests/xe_wa_test.c index ff0e2502b39f..21601e9df353 100644 --- a/drivers/gpu/drm/xe/tests/xe_wa_test.c +++ b/drivers/gpu/drm/xe/tests/xe_wa_test.c @@ -43,9 +43,6 @@ static int xe_wa_test_init(struct kunit *test) xe_gt_mmio_init(gt); } - if (!param->graphics_verx100) - xe->info.step = param->step; - /* TODO: init hw engines for engine/LRC WAs */ xe->drm.dev = dev; test->priv = xe; -- cgit v1.2.3 From 13bebc7171e6fd47ad7b28989c08283508fb4389 Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Tue, 9 Jun 2026 17:17:39 -0300 Subject: drm/xe: Add graphics/media IPs and their step info to xe_probed_info On GMDID-based platforms, the driver needs to probe the hardware by reading GMDID registers in order to identify the graphics/media/display IPs that are present in the platform as well as their stepping values. Currently, xe_info_init() has such a probing logic, but that task should be rather responsibility of xe_probe_info(). As such, move it to the latter. For pre-GMDID platforms, the IPs are identified via PCI devid and revid fields, which is arguably also hardware dependent. So do the same for those platforms. Reviewed-by: Dnyaneshwar Bhadane Reviewed-by: Violet Monti Link: https://patch.msgid.link/20260609-xe-probe-info-v1-7-21e83e188e60@intel.com Signed-off-by: Gustavo Sousa --- drivers/gpu/drm/xe/tests/xe_pci.c | 44 ++++++++++---------- drivers/gpu/drm/xe/xe_pci.c | 88 ++++++++++++++++++++++++--------------- 2 files changed, 77 insertions(+), 55 deletions(-) diff --git a/drivers/gpu/drm/xe/tests/xe_pci.c b/drivers/gpu/drm/xe/tests/xe_pci.c index a665d5dbc472..cd64b1d614c8 100644 --- a/drivers/gpu/drm/xe/tests/xe_pci.c +++ b/drivers/gpu/drm/xe/tests/xe_pci.c @@ -311,31 +311,35 @@ 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 int fake_read_gmdid(struct xe_device *xe, enum xe_gmdid_type type, - u32 *ver, u32 *revid) -{ - struct kunit *test = kunit_get_current_test(); - struct xe_pci_fake_data *data = test->priv; - - if (type == GMDID_MEDIA) { - *ver = data->media_verx100; - *revid = xe_step_to_gmdid(data->step.media); - } else { - *ver = data->graphics_verx100; - *revid = xe_step_to_gmdid(data->step.graphics); - } - - return 0; -} - static void fake_xe_info_probe_tile_count(struct xe_device *xe) { /* Nothing to do, just use the statically defined value. */ } static int fake_probe_info(struct xe_device *xe, + const struct xe_device_desc *desc, + struct xe_pci_fake_data *data, struct xe_probed_info *probed_info) { + if (!data || desc->pre_gmdid_graphics_ip) { + probed_info->graphics_ip = desc->pre_gmdid_graphics_ip; + probed_info->media_ip = desc->pre_gmdid_media_ip; + } else { + probed_info->graphics_ip = find_graphics_ip(data->graphics_verx100); + + if (data->media_verx100) { + probed_info->media_ip = find_media_ip(data->media_verx100); + xe_assert(xe, probed_info->media_ip); + } + } + + xe_assert(xe, probed_info->graphics_ip); + if (!probed_info->graphics_ip) + return -ENODEV; + + if (data) + probed_info->step = data->step; + return 0; } @@ -377,20 +381,16 @@ done: xe->sriov.__mode = data && data->sriov_mode ? data->sriov_mode : XE_SRIOV_MODE_NONE; - 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); - err = fake_probe_info(xe, &probed_info); + err = fake_probe_info(xe, desc, data, &probed_info); if (err) return err; xe_info_init_early(xe, desc, subplatform_desc, &probed_info); xe_info_init(xe, desc, &probed_info); - if (data && !data->graphics_verx100) - xe->info.step = data->step; - return 0; } EXPORT_SYMBOL_IF_KUNIT(xe_pci_fake_device_init); diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index fa43853eb591..ec1967e3e064 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -602,8 +602,6 @@ static int read_gmdid(struct xe_device *xe, enum xe_gmdid_type type, u32 *ver, u struct xe_reg gmdid_reg = GMD_ID; u32 val; - KUNIT_STATIC_STUB_REDIRECT(read_gmdid, xe, type, ver, revid); - if (IS_SRIOV_VF(xe)) { /* * To get the value of the GMDID register, VFs must obtain it @@ -733,6 +731,8 @@ struct xe_probed_info { u16 devid; u8 revid; struct xe_step_info step; + const struct xe_ip *graphics_ip; + const struct xe_ip *media_ip; }; /* @@ -926,12 +926,59 @@ static struct xe_gt *alloc_media_gt(struct xe_tile *tile, return gt; } +static int xe_probe_ips(struct xe_device *xe, + const struct xe_device_desc *desc, + struct xe_probed_info *probed_info) +{ + /* + * If this platform supports GMD_ID, we'll detect the proper IP + * descriptor to use from hardware registers. + * desc->pre_gmdid_graphics_ip will only ever be set at this point for + * platforms before GMD_ID. In that case the IP descriptions and + * versions are simply derived from that. + */ + if (desc->pre_gmdid_graphics_ip) { + probed_info->graphics_ip = desc->pre_gmdid_graphics_ip; + probed_info->media_ip = desc->pre_gmdid_media_ip; + xe_step_pre_gmdid_get(xe, &probed_info->step); + } else { + int err; + u32 graphics_revid, media_revid; + + xe_assert(xe, !desc->pre_gmdid_media_ip); + + err = handle_gmdid(xe, &probed_info->graphics_ip, &probed_info->media_ip, + &graphics_revid, &media_revid); + if (err) + return err; + + xe_step_gmdid_get(xe, graphics_revid, media_revid, &probed_info->step); + } + + /* + * If we couldn't detect the graphics IP, that's considered a fatal + * error and we should abort driver load. Failing to detect media + * IP is non-fatal; we'll just proceed without enabling media support. + */ + if (!probed_info->graphics_ip) + return -ENODEV; + + return 0; +} + /* * Probe from the hardware the info required by xe_info_init(). */ static int xe_probe_info(struct xe_device *xe, + const struct xe_device_desc *desc, struct xe_probed_info *probed_info) { + int err; + + err = xe_probe_ips(xe, desc, probed_info); + if (err) + return err; + return 0; } @@ -945,44 +992,19 @@ static int xe_info_init(struct xe_device *xe, const struct xe_device_desc *desc, struct xe_probed_info *probed_info) { - u32 graphics_gmdid_revid = 0, media_gmdid_revid = 0; const struct xe_ip *graphics_ip; const struct xe_ip *media_ip; const struct xe_graphics_desc *graphics_desc; const struct xe_media_desc *media_desc; struct xe_tile *tile; struct xe_gt *gt; - int ret; u8 id; - /* - * If this platform supports GMD_ID, we'll detect the proper IP - * descriptor to use from hardware registers. - * desc->pre_gmdid_graphics_ip will only ever be set at this point for - * platforms before GMD_ID. In that case the IP descriptions and - * versions are simply derived from that. - */ - if (desc->pre_gmdid_graphics_ip) { - graphics_ip = desc->pre_gmdid_graphics_ip; - media_ip = desc->pre_gmdid_media_ip; - xe_step_pre_gmdid_get(xe, &xe->info.step); - } else { - xe_assert(xe, !desc->pre_gmdid_media_ip); - ret = handle_gmdid(xe, &graphics_ip, &media_ip, - &graphics_gmdid_revid, &media_gmdid_revid); - if (ret) - return ret; - - xe_step_gmdid_get(xe, graphics_gmdid_revid, media_gmdid_revid, &xe->info.step); - } - - /* - * If we couldn't detect the graphics IP, that's considered a fatal - * error and we should abort driver load. Failing to detect media - * IP is non-fatal; we'll just proceed without enabling media support. - */ - if (!graphics_ip) - return -ENODEV; + graphics_ip = probed_info->graphics_ip; + media_ip = probed_info->media_ip; + xe->info.step.basedie = probed_info->step.basedie; + xe->info.step.graphics = probed_info->step.graphics; + xe->info.step.media = probed_info->step.media; xe->info.graphics_verx100 = graphics_ip->verx100; xe->info.graphics_name = graphics_ip->name; @@ -1175,7 +1197,7 @@ static int xe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) return err; - err = xe_probe_info(xe, &probed_info); + err = xe_probe_info(xe, desc, &probed_info); if (err) return err; -- cgit v1.2.3 From 723c3407fb8b4d3a31ddb56cd52ef5194d7684fd Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Tue, 9 Jun 2026 17:17:40 -0300 Subject: drm/xe: Don't initialize tile_count in xe_info_init_early() The value of xe->info.tile_count is only really valid after xe_info_probe_tile_count(). Any use of tile_count before that point is invalid and, consequently, initializing it in xe_info_init_early() is pointless. Move the initialization to xe_info_probe_tile_count(). Reviewed-by: Dnyaneshwar Bhadane Reviewed-by: Violet Monti Link: https://patch.msgid.link/20260609-xe-probe-info-v1-8-21e83e188e60@intel.com Signed-off-by: Gustavo Sousa --- drivers/gpu/drm/xe/tests/xe_pci.c | 5 +++-- drivers/gpu/drm/xe/xe_pci.c | 10 ++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/xe/tests/xe_pci.c b/drivers/gpu/drm/xe/tests/xe_pci.c index cd64b1d614c8..31ec41aa997d 100644 --- a/drivers/gpu/drm/xe/tests/xe_pci.c +++ b/drivers/gpu/drm/xe/tests/xe_pci.c @@ -311,9 +311,10 @@ 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_xe_info_probe_tile_count(struct xe_device *xe) +static void fake_xe_info_probe_tile_count(struct xe_device *xe, + const struct xe_device_desc *desc) { - /* Nothing to do, just use the statically defined value. */ + xe->info.tile_count = 1 + desc->max_remote_tiles; } static int fake_probe_info(struct xe_device *xe, diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index ec1967e3e064..674948f55d51 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -813,7 +813,6 @@ static int xe_info_init_early(struct xe_device *xe, xe_assert(xe, desc->max_gt_per_tile > 0); xe_assert(xe, desc->max_gt_per_tile <= XE_MAX_GT_PER_TILE); xe->info.max_gt_per_tile = desc->max_gt_per_tile; - xe->info.tile_count = 1 + desc->max_remote_tiles; err = xe_tile_init_early(xe_device_get_root_tile(xe), xe, 0); if (err) @@ -825,13 +824,16 @@ static int xe_info_init_early(struct xe_device *xe, /* * Possibly override number of tile based on configuration register. */ -static void xe_info_probe_tile_count(struct xe_device *xe) +static void xe_info_probe_tile_count(struct xe_device *xe, + const struct xe_device_desc *desc) { struct xe_mmio *mmio; u8 tile_count; u32 mtcfg; - KUNIT_STATIC_STUB_REDIRECT(xe_info_probe_tile_count, xe); + KUNIT_STATIC_STUB_REDIRECT(xe_info_probe_tile_count, xe, desc); + + xe->info.tile_count = 1 + desc->max_remote_tiles; /* * Probe for tile count only for platforms that support multiple @@ -1037,7 +1039,7 @@ static int xe_info_init(struct xe_device *xe, xe->info.has_soc_remapper_telem = 0; } - xe_info_probe_tile_count(xe); + xe_info_probe_tile_count(xe, desc); for_each_remote_tile(tile, xe, id) { int err; -- cgit v1.2.3 From 820de07bba7b7c97e0f52e1d66bf6147a25ab67f Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Tue, 9 Jun 2026 17:17:41 -0300 Subject: drm/xe: Add tile_count to xe_probed_info On multi-tile platforms, we need to probe the hardware for the number of tiles that are present in the platform. That means that we should do that as part of xe_probe_info() instead of xe_info_init(). Do that. Reviewed-by: Dnyaneshwar Bhadane Reviewed-by: Violet Monti Link: https://patch.msgid.link/20260609-xe-probe-info-v1-9-21e83e188e60@intel.com Signed-off-by: Gustavo Sousa --- drivers/gpu/drm/xe/tests/xe_pci.c | 11 ++--------- drivers/gpu/drm/xe/xe_pci.c | 27 +++++++++++++-------------- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/xe/tests/xe_pci.c b/drivers/gpu/drm/xe/tests/xe_pci.c index 31ec41aa997d..8df9029afcd3 100644 --- a/drivers/gpu/drm/xe/tests/xe_pci.c +++ b/drivers/gpu/drm/xe/tests/xe_pci.c @@ -311,17 +311,13 @@ 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_xe_info_probe_tile_count(struct xe_device *xe, - const struct xe_device_desc *desc) -{ - xe->info.tile_count = 1 + desc->max_remote_tiles; -} - static int fake_probe_info(struct xe_device *xe, const struct xe_device_desc *desc, struct xe_pci_fake_data *data, struct xe_probed_info *probed_info) { + probed_info->tile_count = 1 + desc->max_remote_tiles; + if (!data || desc->pre_gmdid_graphics_ip) { probed_info->graphics_ip = desc->pre_gmdid_graphics_ip; probed_info->media_ip = desc->pre_gmdid_media_ip; @@ -382,9 +378,6 @@ done: xe->sriov.__mode = data && data->sriov_mode ? data->sriov_mode : XE_SRIOV_MODE_NONE; - kunit_activate_static_stub(test, xe_info_probe_tile_count, - fake_xe_info_probe_tile_count); - err = fake_probe_info(xe, desc, data, &probed_info); if (err) return err; diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index 674948f55d51..91af603e9431 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -730,6 +730,7 @@ static int handle_gmdid(struct xe_device *xe, struct xe_probed_info { u16 devid; u8 revid; + u8 tile_count; struct xe_step_info step; const struct xe_ip *graphics_ip; const struct xe_ip *media_ip; @@ -821,25 +822,21 @@ static int xe_info_init_early(struct xe_device *xe, return 0; } -/* - * Possibly override number of tile based on configuration register. - */ -static void xe_info_probe_tile_count(struct xe_device *xe, - const struct xe_device_desc *desc) +static void xe_probe_tile_count(struct xe_device *xe, + const struct xe_device_desc *desc, + struct xe_probed_info *probed_info) { struct xe_mmio *mmio; u8 tile_count; u32 mtcfg; - KUNIT_STATIC_STUB_REDIRECT(xe_info_probe_tile_count, xe, desc); - - xe->info.tile_count = 1 + desc->max_remote_tiles; + probed_info->tile_count = 1 + desc->max_remote_tiles; /* * Probe for tile count only for platforms that support multiple * tiles. */ - if (xe->info.tile_count == 1) + if (probed_info->tile_count == 1) return; mmio = xe_root_tile_mmio(xe); @@ -852,10 +849,10 @@ static void xe_info_probe_tile_count(struct xe_device *xe, mtcfg = xe_mmio_read32(mmio, XEHP_MTCFG_ADDR); tile_count = REG_FIELD_GET(TILE_COUNT, mtcfg) + 1; - if (tile_count < xe->info.tile_count) { + if (tile_count < probed_info->tile_count) { drm_info(&xe->drm, "tile_count: %d, reduced_tile_count %d\n", - xe->info.tile_count, tile_count); - xe->info.tile_count = tile_count; + probed_info->tile_count, tile_count); + probed_info->tile_count = tile_count; } } @@ -977,6 +974,8 @@ static int xe_probe_info(struct xe_device *xe, { int err; + xe_probe_tile_count(xe, desc, probed_info); + err = xe_probe_ips(xe, desc, probed_info); if (err) return err; @@ -1004,6 +1003,8 @@ static int xe_info_init(struct xe_device *xe, graphics_ip = probed_info->graphics_ip; media_ip = probed_info->media_ip; + + xe->info.tile_count = probed_info->tile_count; xe->info.step.basedie = probed_info->step.basedie; xe->info.step.graphics = probed_info->step.graphics; xe->info.step.media = probed_info->step.media; @@ -1039,8 +1040,6 @@ static int xe_info_init(struct xe_device *xe, xe->info.has_soc_remapper_telem = 0; } - xe_info_probe_tile_count(xe, desc); - for_each_remote_tile(tile, xe, id) { int err; -- cgit v1.2.3