From e70711be0d0ebdd0a9213446b657fe0815e38017 Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Mon, 5 Jan 2026 13:37:50 +0530 Subject: drm/xe/i2c: Force polling mode in survivability SGUnit interrupts are not initialized in survivability. Force I2C controller to polling mode while in survivability. v2: Use helper function instead of manual check (Riana) Signed-off-by: Raag Jadav Reviewed-by: Heikki Krogerus Link: https://patch.msgid.link/20260105080750.16605-1-raag.jadav@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/xe_i2c.c | 9 ++++++--- drivers/gpu/drm/xe/xe_survivability_mode.c | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_i2c.c b/drivers/gpu/drm/xe/xe_i2c.c index 8eccbae05705..befc77e46eae 100644 --- a/drivers/gpu/drm/xe/xe_i2c.c +++ b/drivers/gpu/drm/xe/xe_i2c.c @@ -31,6 +31,7 @@ #include "xe_i2c.h" #include "xe_mmio.h" #include "xe_platform_types.h" +#include "xe_survivability_mode.h" /** * DOC: Xe I2C devices @@ -213,11 +214,13 @@ static const struct irq_domain_ops xe_i2c_irq_ops = { .map = xe_i2c_irq_map, }; -static int xe_i2c_create_irq(struct xe_i2c *i2c) +static int xe_i2c_create_irq(struct xe_device *xe) { + struct xe_i2c *i2c = xe->i2c; struct irq_domain *domain; - if (!(i2c->ep.capabilities & XE_I2C_EP_CAP_IRQ)) + if (!(i2c->ep.capabilities & XE_I2C_EP_CAP_IRQ) || + xe_survivability_mode_is_boot_enabled(xe)) return 0; domain = irq_domain_create_linear(dev_fwnode(i2c->drm_dev), 1, &xe_i2c_irq_ops, NULL); @@ -351,7 +354,7 @@ int xe_i2c_probe(struct xe_device *xe) if (ret) return ret; - ret = xe_i2c_create_irq(i2c); + ret = xe_i2c_create_irq(xe); if (ret) goto err_unregister_notifier; diff --git a/drivers/gpu/drm/xe/xe_survivability_mode.c b/drivers/gpu/drm/xe/xe_survivability_mode.c index 4c716182ad3b..31456f432fc8 100644 --- a/drivers/gpu/drm/xe/xe_survivability_mode.c +++ b/drivers/gpu/drm/xe/xe_survivability_mode.c @@ -321,7 +321,7 @@ static int enable_boot_survivability_mode(struct pci_dev *pdev) if (ret) return ret; - /* Make sure xe_heci_gsc_init() knows about survivability mode */ + /* Make sure xe_heci_gsc_init() and xe_i2c_probe() are aware of survivability */ survivability->mode = true; xe_heci_gsc_init(xe); -- cgit v1.2.3 From caaed1dda7df9b4e21d439bb5e7750d4af4f1e78 Mon Sep 17 00:00:00 2001 From: Niranjana Vishwanathapura Date: Tue, 6 Jan 2026 11:10:50 -0800 Subject: Revert "drm/xe/multi_queue: Support active group after primary is destroyed" This reverts commit 3131a43ecb346ae3b5287ee195779fc38c6fcd11. There is no must have requirement for this feature from Compute UMD. Signed-off-by: Niranjana Vishwanathapura Reviewed-by: Matthew Brost Link: https://patch.msgid.link/20260106191051.2866538-5-niranjana.vishwanathapura@intel.com --- drivers/gpu/drm/xe/xe_device.c | 7 +--- drivers/gpu/drm/xe/xe_exec_queue.c | 55 ++------------------------------ drivers/gpu/drm/xe/xe_exec_queue.h | 2 -- drivers/gpu/drm/xe/xe_exec_queue_types.h | 4 --- include/uapi/drm/xe_drm.h | 4 --- 5 files changed, 3 insertions(+), 69 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index e101d290b2a6..f4741cbe4c45 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -180,12 +180,7 @@ static void xe_file_close(struct drm_device *dev, struct drm_file *file) xa_for_each(&xef->exec_queue.xa, idx, q) { if (q->vm && q->hwe->hw_engine_group) xe_hw_engine_group_del_exec_queue(q->hwe->hw_engine_group, q); - - if (xe_exec_queue_is_multi_queue_primary(q)) - xe_exec_queue_group_kill_put(q->multi_queue.group); - else - xe_exec_queue_kill(q); - + xe_exec_queue_kill(q); xe_exec_queue_put(q); } xa_for_each(&xef->vm.xa, idx, vm) diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c index 0b9e074b022f..529a40ca4002 100644 --- a/drivers/gpu/drm/xe/xe_exec_queue.c +++ b/drivers/gpu/drm/xe/xe_exec_queue.c @@ -467,26 +467,6 @@ struct xe_exec_queue *xe_exec_queue_create_bind(struct xe_device *xe, } ALLOW_ERROR_INJECTION(xe_exec_queue_create_bind, ERRNO); -static void xe_exec_queue_group_kill(struct kref *ref) -{ - struct xe_exec_queue_group *group = container_of(ref, struct xe_exec_queue_group, - kill_refcount); - xe_exec_queue_kill(group->primary); -} - -static inline void xe_exec_queue_group_kill_get(struct xe_exec_queue_group *group) -{ - kref_get(&group->kill_refcount); -} - -void xe_exec_queue_group_kill_put(struct xe_exec_queue_group *group) -{ - if (!group) - return; - - kref_put(&group->kill_refcount, xe_exec_queue_group_kill); -} - void xe_exec_queue_destroy(struct kref *ref) { struct xe_exec_queue *q = container_of(ref, struct xe_exec_queue, refcount); @@ -716,7 +696,6 @@ static int xe_exec_queue_group_init(struct xe_device *xe, struct xe_exec_queue * group->primary = q; group->cgp_bo = bo; INIT_LIST_HEAD(&group->list); - kref_init(&group->kill_refcount); xa_init_flags(&group->xa, XA_FLAGS_ALLOC1); mutex_init(&group->list_lock); q->multi_queue.group = group; @@ -792,11 +771,6 @@ static int xe_exec_queue_group_add(struct xe_device *xe, struct xe_exec_queue *q q->multi_queue.pos = pos; - if (group->primary->multi_queue.keep_active) { - xe_exec_queue_group_kill_get(group); - q->multi_queue.keep_active = true; - } - return 0; } @@ -810,11 +784,6 @@ static void xe_exec_queue_group_delete(struct xe_device *xe, struct xe_exec_queu lrc = xa_erase(&group->xa, q->multi_queue.pos); xe_assert(xe, lrc); xe_lrc_put(lrc); - - if (q->multi_queue.keep_active) { - xe_exec_queue_group_kill_put(group); - q->multi_queue.keep_active = false; - } } static int exec_queue_set_multi_group(struct xe_device *xe, struct xe_exec_queue *q, @@ -836,24 +805,12 @@ static int exec_queue_set_multi_group(struct xe_device *xe, struct xe_exec_queue return -EINVAL; if (value & DRM_XE_MULTI_GROUP_CREATE) { - if (XE_IOCTL_DBG(xe, value & ~(DRM_XE_MULTI_GROUP_CREATE | - DRM_XE_MULTI_GROUP_KEEP_ACTIVE))) - return -EINVAL; - - /* - * KEEP_ACTIVE is not supported in preempt fence mode as in that mode, - * VM_DESTROY ioctl expects all exec queues of that VM are already killed. - */ - if (XE_IOCTL_DBG(xe, (value & DRM_XE_MULTI_GROUP_KEEP_ACTIVE) && - xe_vm_in_preempt_fence_mode(q->vm))) + if (XE_IOCTL_DBG(xe, value & ~DRM_XE_MULTI_GROUP_CREATE)) return -EINVAL; q->multi_queue.valid = true; q->multi_queue.is_primary = true; q->multi_queue.pos = 0; - if (value & DRM_XE_MULTI_GROUP_KEEP_ACTIVE) - q->multi_queue.keep_active = true; - return 0; } @@ -1419,11 +1376,6 @@ void xe_exec_queue_kill(struct xe_exec_queue *q) q->ops->kill(q); xe_vm_remove_compute_exec_queue(q->vm, q); - - if (!xe_exec_queue_is_multi_queue_primary(q) && q->multi_queue.keep_active) { - xe_exec_queue_group_kill_put(q->multi_queue.group); - q->multi_queue.keep_active = false; - } } int xe_exec_queue_destroy_ioctl(struct drm_device *dev, void *data, @@ -1450,10 +1402,7 @@ int xe_exec_queue_destroy_ioctl(struct drm_device *dev, void *data, if (q->vm && q->hwe->hw_engine_group) xe_hw_engine_group_del_exec_queue(q->hwe->hw_engine_group, q); - if (xe_exec_queue_is_multi_queue_primary(q)) - xe_exec_queue_group_kill_put(q->multi_queue.group); - else - xe_exec_queue_kill(q); + xe_exec_queue_kill(q); trace_xe_exec_queue_close(q); xe_exec_queue_put(q); diff --git a/drivers/gpu/drm/xe/xe_exec_queue.h b/drivers/gpu/drm/xe/xe_exec_queue.h index b5ad975d7e97..b1e51789128f 100644 --- a/drivers/gpu/drm/xe/xe_exec_queue.h +++ b/drivers/gpu/drm/xe/xe_exec_queue.h @@ -113,8 +113,6 @@ static inline struct xe_exec_queue *xe_exec_queue_multi_queue_primary(struct xe_ return xe_exec_queue_is_multi_queue(q) ? q->multi_queue.group->primary : q; } -void xe_exec_queue_group_kill_put(struct xe_exec_queue_group *group); - bool xe_exec_queue_is_lr(struct xe_exec_queue *q); bool xe_exec_queue_is_idle(struct xe_exec_queue *q); diff --git a/drivers/gpu/drm/xe/xe_exec_queue_types.h b/drivers/gpu/drm/xe/xe_exec_queue_types.h index 67ea5eebf70b..5fc516b0bb77 100644 --- a/drivers/gpu/drm/xe/xe_exec_queue_types.h +++ b/drivers/gpu/drm/xe/xe_exec_queue_types.h @@ -62,8 +62,6 @@ struct xe_exec_queue_group { struct list_head list; /** @list_lock: Secondary queue list lock */ struct mutex list_lock; - /** @kill_refcount: ref count to kill primary queue */ - struct kref kill_refcount; /** @sync_pending: CGP_SYNC_DONE g2h response pending */ bool sync_pending; /** @banned: Group banned */ @@ -163,8 +161,6 @@ struct xe_exec_queue { u8 valid:1; /** @multi_queue.is_primary: Is primary queue (Q0) of the group */ u8 is_primary:1; - /** @multi_queue.keep_active: Keep the group active after primary is destroyed */ - u8 keep_active:1; } multi_queue; /** @sched_props: scheduling properties */ diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h index bb69f9b30c7d..077e66a682e2 100644 --- a/include/uapi/drm/xe_drm.h +++ b/include/uapi/drm/xe_drm.h @@ -1280,9 +1280,6 @@ struct drm_xe_vm_bind { * then a new multi-queue group is created with this queue as the primary queue * (Q0). Otherwise, the queue gets added to the multi-queue group whose primary * queue's exec_queue_id is specified in the lower 32 bits of the 'value' field. - * If the extension's 'value' field has %DRM_XE_MULTI_GROUP_KEEP_ACTIVE flag - * set, then the multi-queue group is kept active after the primary queue is - * destroyed. * All the other non-relevant bits of extension's 'value' field while adding the * primary or the secondary queues of the group must be set to 0. * - %DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_QUEUE_PRIORITY - Set the queue @@ -1331,7 +1328,6 @@ struct drm_xe_exec_queue_create { #define DRM_XE_EXEC_QUEUE_SET_HANG_REPLAY_STATE 3 #define DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_GROUP 4 #define DRM_XE_MULTI_GROUP_CREATE (1ull << 63) -#define DRM_XE_MULTI_GROUP_KEEP_ACTIVE (1ull << 62) #define DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_QUEUE_PRIORITY 5 /** @extensions: Pointer to the first extension struct, if any */ __u64 extensions; -- cgit v1.2.3 From 051114652b6b78c18720dbc6fef36ddb5e1da55b Mon Sep 17 00:00:00 2001 From: Niranjana Vishwanathapura Date: Tue, 6 Jan 2026 11:10:51 -0800 Subject: drm/xe/doc: Remove KEEP_ACTIVE feature The KEEP_ACTIVE feature is being reverted, update documentation. Signed-off-by: Niranjana Vishwanathapura Reviewed-by: Matthew Brost Link: https://patch.msgid.link/20260106191051.2866538-6-niranjana.vishwanathapura@intel.com --- drivers/gpu/drm/xe/xe_exec_queue.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c index 529a40ca4002..b5737563ee14 100644 --- a/drivers/gpu/drm/xe/xe_exec_queue.c +++ b/drivers/gpu/drm/xe/xe_exec_queue.c @@ -84,9 +84,8 @@ * group is destroyed. The secondary queues hold a reference to the primary * queue thus preventing the group from being destroyed when user destroys * the primary queue. Once the primary queue is destroyed, secondary queues - * can't be added to the queue group, but they can continue to submit the - * jobs if the DRM_XE_MULTI_GROUP_KEEP_ACTIVE flag is set during the multi - * queue group creation. + * can't be added to the queue group and new job submissions on existing + * secondary queues are not allowed. * * The queues of a multi queue group can set their priority within the group * through the DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_QUEUE_PRIORITY property. -- cgit v1.2.3 From 7c0c19c076ffe84b8bcd5f927eb47452837f2c99 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Tue, 6 Jan 2026 13:34:43 -0800 Subject: drm/xe: Validate preferred system memory placement in xe_svm_range_validate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensure preferred system memory placement is checked in xe_svm_range_validate when dpagemap is NULL. Without this check, a prefetch to system memory may become a no-op because device memory is considered a valid placement. Cc: Thomas Hellström Fixes: 238dbc9d9f4a ("drm/xe: Use the vma attibute drm_pagemap to select where to migrate") Signed-off-by: Matthew Brost Reviewed-by: Himal Prasad Ghimiray Link: https://patch.msgid.link/20260106213443.1866797-1-matthew.brost@intel.com --- drivers/gpu/drm/xe/xe_svm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c index fa2ee2c08f31..213f0334518a 100644 --- a/drivers/gpu/drm/xe/xe_svm.c +++ b/drivers/gpu/drm/xe/xe_svm.c @@ -988,6 +988,8 @@ bool xe_svm_range_validate(struct xe_vm *vm, ret = (range->tile_present & ~range->tile_invalidated & tile_mask) == tile_mask; if (dpagemap) ret = ret && xe_svm_range_has_pagemap_locked(range, dpagemap); + else + ret = ret && !range->base.pages.dpagemap; xe_svm_notifier_unlock(vm); -- cgit v1.2.3 From cc54eabdfbf0c5b6638edc50002cfafac1f1e18b Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Wed, 7 Jan 2026 12:57:32 -0800 Subject: drm/xe: Adjust page count tracepoints in shrinker Page accounting can change via the shrinker without calling xe_ttm_tt_unpopulate(), which normally updates page count tracepoints through update_global_total_pages. Add a call to update_global_total_pages when the shrinker successfully shrinks a BO. v2: - Don't adjust global accounting when pinning (Stuart) Cc: stable@vger.kernel.org Fixes: ce3d39fae3d3 ("drm/xe/bo: add GPU memory trace points") Signed-off-by: Matthew Brost Reviewed-by: Stuart Summers Link: https://patch.msgid.link/20260107205732.2267541-1-matthew.brost@intel.com --- drivers/gpu/drm/xe/xe_bo.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index 8b6474cd3eaf..6ab52fa397e3 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -1054,6 +1054,7 @@ static long xe_bo_shrink_purge(struct ttm_operation_ctx *ctx, unsigned long *scanned) { struct xe_device *xe = ttm_to_xe_device(bo->bdev); + struct ttm_tt *tt = bo->ttm; long lret; /* Fake move to system, without copying data. */ @@ -1078,8 +1079,10 @@ static long xe_bo_shrink_purge(struct ttm_operation_ctx *ctx, .writeback = false, .allow_move = false}); - if (lret > 0) + if (lret > 0) { xe_ttm_tt_account_subtract(xe, bo->ttm); + update_global_total_pages(bo->bdev, -(long)tt->num_pages); + } return lret; } @@ -1165,8 +1168,10 @@ long xe_bo_shrink(struct ttm_operation_ctx *ctx, struct ttm_buffer_object *bo, if (needs_rpm) xe_pm_runtime_put(xe); - if (lret > 0) + if (lret > 0) { xe_ttm_tt_account_subtract(xe, tt); + update_global_total_pages(bo->bdev, -(long)tt->num_pages); + } out_unref: xe_bo_put(xe_bo); -- cgit v1.2.3 From 3902846af36beca676735540470a115b3d637263 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Wed, 7 Jan 2026 10:27:15 -0800 Subject: drm/pagemap Fix error paths in drm_pagemap_migrate_to_devmem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid unlocking and putting device pages unless they were successfully locked, and do not calculate migrated_pages on error paths. Cc: Thomas Hellström Fixes: 75af93b3f5d0 ("drm/pagemap, drm/xe: Support destination migration over interconnect") Signed-off-by: Matthew Brost Reviewed-by: Francois Dugast Link: https://patch.msgid.link/20260107182716.2236607-2-matthew.brost@intel.com --- drivers/gpu/drm/drm_pagemap.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_pagemap.c b/drivers/gpu/drm/drm_pagemap.c index ba099aa7c52f..aa43a8475100 100644 --- a/drivers/gpu/drm/drm_pagemap.c +++ b/drivers/gpu/drm/drm_pagemap.c @@ -582,7 +582,7 @@ int drm_pagemap_migrate_to_devmem(struct drm_pagemap_devmem *devmem_allocation, err = ops->populate_devmem_pfn(devmem_allocation, npages, migrate.dst); if (err) - goto err_finalize; + goto err_aborted_migration; own_pages = 0; @@ -621,8 +621,10 @@ int drm_pagemap_migrate_to_devmem(struct drm_pagemap_devmem *devmem_allocation, err = drm_pagemap_migrate_range(devmem_allocation, migrate.src, migrate.dst, pages, pagemap_addr, &last, &cur, mdetails); - if (err) + if (err) { + npages = i + 1; goto err_finalize; + } } cur.start = npages; cur.ops = NULL; /* Force migration */ @@ -646,7 +648,7 @@ err_finalize: err_aborted_migration: migrate_vma_pages(&migrate); - for (i = 0; i < npages;) { + for (i = 0; !err && i < npages;) { struct page *page = migrate_pfn_to_page(migrate.src[i]); unsigned long nr_pages = page ? NR_PAGES(folio_order(page_folio(page))) : 1; -- cgit v1.2.3 From 10dd1eaa80a56d3cf6d7c36b5269c8fed617f001 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Wed, 7 Jan 2026 10:27:16 -0800 Subject: drm/pagemap: Disable device-to-device migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Device-to-device migration is causing xe_exec_system_allocator --r *race*no* to intermittently fail with engine resets and a kernel hang on a page lock. This should work but is clearly buggy somewhere. Disable device-to-device migration in the interim until the issue can be root-caused. The only downside of disabling device-to-device migration is that memory will bounce through system memory during migration. However, this path should be rare, as it only occurs when madvise attributes are changed or atomics are used. Cc: Thomas Hellström Fixes: ec265e1f1cfc ("drm/pagemap: Support source migration over interconnect") Signed-off-by: Matthew Brost Reviewed-by: Francois Dugast Link: https://patch.msgid.link/20260107182716.2236607-3-matthew.brost@intel.com --- drivers/gpu/drm/drm_pagemap.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_pagemap.c b/drivers/gpu/drm/drm_pagemap.c index aa43a8475100..03ee39a761a4 100644 --- a/drivers/gpu/drm/drm_pagemap.c +++ b/drivers/gpu/drm/drm_pagemap.c @@ -480,8 +480,18 @@ int drm_pagemap_migrate_to_devmem(struct drm_pagemap_devmem *devmem_allocation, .start = start, .end = end, .pgmap_owner = pagemap->owner, - .flags = MIGRATE_VMA_SELECT_SYSTEM | MIGRATE_VMA_SELECT_DEVICE_COHERENT | - MIGRATE_VMA_SELECT_DEVICE_PRIVATE, + /* + * FIXME: MIGRATE_VMA_SELECT_DEVICE_PRIVATE intermittently + * causes 'xe_exec_system_allocator --r *race*no*' to trigger aa + * engine reset and a hard hang due to getting stuck on a folio + * lock. This should work and needs to be root-caused. The only + * downside of not selecting MIGRATE_VMA_SELECT_DEVICE_PRIVATE + * is that device-to-device migrations won’t work; instead, + * memory will bounce through system memory. This path should be + * rare and only occur when the madvise attributes of memory are + * changed or atomics are being used. + */ + .flags = MIGRATE_VMA_SELECT_SYSTEM | MIGRATE_VMA_SELECT_DEVICE_COHERENT, }; unsigned long i, npages = npages_in_range(start, end); unsigned long own_pages = 0, migrated_pages = 0; -- cgit v1.2.3 From 4e88de313ff4d1c67b644b1f39f9fb4089711b71 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Thu, 8 Jan 2026 10:19:45 -0800 Subject: drm/xe/nvls: Define GuC firmware for NVL-S Although NVL-S has a similar Xe3 to PTL/WCL, it requires a unique GuC firmware. Signed-off-by: Matt Roper Reviewed-by: Lucas De Marchi Link: https://lore.kernel.org/r/20251016-xe3p-v3-12-3dd173a3097a@intel.com Signed-off-by: Lucas De Marchi Signed-off-by: Julia Filipchuk Link: https://patch.msgid.link/20260108181956.1254908-9-julia.filipchuk@intel.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_uc_fw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/xe/xe_uc_fw.c b/drivers/gpu/drm/xe/xe_uc_fw.c index dcb4a32e7a64..85544c214274 100644 --- a/drivers/gpu/drm/xe/xe_uc_fw.c +++ b/drivers/gpu/drm/xe/xe_uc_fw.c @@ -115,6 +115,7 @@ 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 644673a69f2b6b7359c78b4a42c5ab17473545f9 Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Sat, 20 Dec 2025 13:06:56 +0530 Subject: drm/xe/pm: Handle GT resume failure We've been historically ignoring GT resume failure. Since the function can return error, handle it properly. v2: Bring up display before bailing (Matt Roper, Rodrigo) Signed-off-by: Raag Jadav Link: https://patch.msgid.link/20251220073657.166810-1-raag.jadav@intel.com Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_pm.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_pm.c b/drivers/gpu/drm/xe/xe_pm.c index 4390ba69610d..559cf5490ac0 100644 --- a/drivers/gpu/drm/xe/xe_pm.c +++ b/drivers/gpu/drm/xe/xe_pm.c @@ -260,10 +260,19 @@ int xe_pm_resume(struct xe_device *xe) xe_irq_resume(xe); - for_each_gt(gt, xe, id) - xe_gt_resume(gt); + for_each_gt(gt, xe, id) { + err = xe_gt_resume(gt); + if (err) + break; + } + /* + * Try to bring up display before bailing from GT resume failure, + * so we don't leave the user clueless with a blank screen. + */ xe_display_pm_resume(xe); + if (err) + goto err; err = xe_bo_restore_late(xe); if (err) @@ -656,10 +665,19 @@ int xe_pm_runtime_resume(struct xe_device *xe) xe_irq_resume(xe); - for_each_gt(gt, xe, id) - xe->d3cold.allowed ? xe_gt_resume(gt) : xe_gt_runtime_resume(gt); + for_each_gt(gt, xe, id) { + err = xe->d3cold.allowed ? xe_gt_resume(gt) : xe_gt_runtime_resume(gt); + if (err) + break; + } + /* + * Try to bring up display before bailing from GT resume failure, + * so we don't leave the user clueless with a blank screen. + */ xe_display_pm_runtime_resume(xe); + if (err) + goto out; if (xe->d3cold.allowed) { err = xe_bo_restore_late(xe); -- cgit v1.2.3 From 17d3c3365ba9e52596855d6acb71c3159be1b9c3 Mon Sep 17 00:00:00 2001 From: Lukasz Laguna Date: Wed, 7 Jan 2026 18:47:38 +0100 Subject: drm/xe: Validate wedged_mode parameter and define enum for modes Check correctness of the wedged_mode parameter input to ensure only supported values are accepted. Additionally, replace magic numbers with a clearly defined enum. Signed-off-by: Lukasz Laguna Reviewed-by: Rodrigo Vivi Link: https://patch.msgid.link/20260107174741.29163-2-lukasz.laguna@intel.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_debugfs.c | 5 ++-- drivers/gpu/drm/xe/xe_device.c | 54 ++++++++++++++++++++++++++++++++---- drivers/gpu/drm/xe/xe_device.h | 2 ++ drivers/gpu/drm/xe/xe_device_types.h | 21 +++++++++++++- drivers/gpu/drm/xe/xe_guc_ads.c | 4 +-- drivers/gpu/drm/xe/xe_guc_capture.c | 9 +++++- drivers/gpu/drm/xe/xe_guc_submit.c | 7 +++-- drivers/gpu/drm/xe/xe_module.c | 10 ++++--- drivers/gpu/drm/xe/xe_module.h | 2 +- 9 files changed, 94 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_debugfs.c b/drivers/gpu/drm/xe/xe_debugfs.c index 0907868b32d6..db2afd60d8bc 100644 --- a/drivers/gpu/drm/xe/xe_debugfs.c +++ b/drivers/gpu/drm/xe/xe_debugfs.c @@ -267,8 +267,9 @@ static ssize_t wedged_mode_set(struct file *f, const char __user *ubuf, if (ret) return ret; - if (wedged_mode > 2) - return -EINVAL; + ret = xe_device_validate_wedged_mode(xe, wedged_mode); + if (ret) + return ret; if (xe->wedged.mode == wedged_mode) return size; diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index f4741cbe4c45..62ec2e2d6436 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -784,7 +784,10 @@ int xe_device_probe_early(struct xe_device *xe) if (err) return err; - xe->wedged.mode = xe_modparam.wedged_mode; + xe->wedged.mode = xe_device_validate_wedged_mode(xe, xe_modparam.wedged_mode) ? + XE_WEDGED_MODE_DEFAULT : xe_modparam.wedged_mode; + drm_dbg(&xe->drm, "wedged_mode: setting mode (%u) %s\n", + xe->wedged.mode, xe_wedged_mode_to_string(xe->wedged.mode)); err = xe_device_vram_alloc(xe); if (err) @@ -1267,10 +1270,10 @@ static void xe_device_wedged_fini(struct drm_device *drm, void *arg) * DOC: Xe Device Wedging * * Xe driver uses drm device wedged uevent as documented in Documentation/gpu/drm-uapi.rst. - * When device is in wedged state, every IOCTL will be blocked and GT cannot be - * used. Certain critical errors like gt reset failure, firmware failures can cause - * the device to be wedged. The default recovery method for a wedged state - * is rebind/bus-reset. + * When device is in wedged state, every IOCTL will be blocked and GT cannot + * be used. The conditions under which the driver declares the device wedged + * depend on the wedged mode configuration (see &enum xe_wedged_mode). The + * default recovery method for a wedged state is rebind/bus-reset. * * Another recovery method is vendor-specific. Below are the cases that send * ``WEDGED=vendor-specific`` recovery method in drm device wedged uevent. @@ -1335,7 +1338,7 @@ void xe_device_declare_wedged(struct xe_device *xe) struct xe_gt *gt; u8 id; - if (xe->wedged.mode == 0) { + if (xe->wedged.mode == XE_WEDGED_MODE_NEVER) { drm_dbg(&xe->drm, "Wedged mode is forcibly disabled\n"); return; } @@ -1369,3 +1372,42 @@ void xe_device_declare_wedged(struct xe_device *xe) drm_dev_wedged_event(&xe->drm, xe->wedged.method, NULL); } } + +/** + * xe_device_validate_wedged_mode - Check if given mode is supported + * @xe: the &xe_device + * @mode: requested mode to validate + * + * Check whether the provided wedged mode is supported. + * + * Return: 0 if mode is supported, error code otherwise. + */ +int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode) +{ + if (mode > XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) { + drm_dbg(&xe->drm, "wedged_mode: invalid value (%u)\n", mode); + return -EINVAL; + } + + return 0; +} + +/** + * xe_wedged_mode_to_string - Convert enum value to string. + * @mode: the &xe_wedged_mode to convert + * + * Returns: wedged mode as a user friendly string. + */ +const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode) +{ + switch (mode) { + case XE_WEDGED_MODE_NEVER: + return "never"; + case XE_WEDGED_MODE_UPON_CRITICAL_ERROR: + return "upon-critical-error"; + case XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET: + return "upon-any-hang-no-reset"; + default: + return ""; + } +} diff --git a/drivers/gpu/drm/xe/xe_device.h b/drivers/gpu/drm/xe/xe_device.h index 3e72fa4609f8..3740143790db 100644 --- a/drivers/gpu/drm/xe/xe_device.h +++ b/drivers/gpu/drm/xe/xe_device.h @@ -194,6 +194,8 @@ static inline bool xe_device_wedged(struct xe_device *xe) void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method); void xe_device_declare_wedged(struct xe_device *xe); +int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode); +const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode); struct xe_file *xe_file_get(struct xe_file *xef); void xe_file_put(struct xe_file *xef); diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index a85be9ba175e..d790129a06db 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -46,6 +46,25 @@ struct xe_pat_ops; struct xe_pxp; struct xe_vram_region; +/** + * enum xe_wedged_mode - possible wedged modes + * @XE_WEDGED_MODE_NEVER: Device will never be declared wedged. + * @XE_WEDGED_MODE_UPON_CRITICAL_ERROR: Device will be declared wedged only + * when critical error occurs like GT reset failure or firmware failure. + * This is the default mode. + * @XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET: Device will be declared wedged on + * any hang. In this mode, engine resets are disabled to avoid automatic + * recovery attempts. This mode is primarily intended for debugging hangs. + */ +enum xe_wedged_mode { + XE_WEDGED_MODE_NEVER = 0, + XE_WEDGED_MODE_UPON_CRITICAL_ERROR = 1, + XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET = 2, +}; + +#define XE_WEDGED_MODE_DEFAULT XE_WEDGED_MODE_UPON_CRITICAL_ERROR +#define XE_WEDGED_MODE_DEFAULT_STR "upon-critical-error" + #define XE_BO_INVALID_OFFSET LONG_MAX #define GRAPHICS_VER(xe) ((xe)->info.graphics_verx100 / 100) @@ -626,7 +645,7 @@ struct xe_device { /** @wedged.flag: Xe device faced a critical error and is now blocked. */ atomic_t flag; /** @wedged.mode: Mode controlled by kernel parameter and debugfs */ - int mode; + enum xe_wedged_mode mode; /** @wedged.method: Recovery method to be sent in the drm device wedged uevent */ unsigned long method; } wedged; diff --git a/drivers/gpu/drm/xe/xe_guc_ads.c b/drivers/gpu/drm/xe/xe_guc_ads.c index 5feeb91426ee..2b47e897d2ea 100644 --- a/drivers/gpu/drm/xe/xe_guc_ads.c +++ b/drivers/gpu/drm/xe/xe_guc_ads.c @@ -451,7 +451,7 @@ static void guc_policies_init(struct xe_guc_ads *ads) ads_blob_write(ads, policies.max_num_work_items, GLOBAL_POLICY_MAX_NUM_WI); - if (xe->wedged.mode == 2) + if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) global_flags |= GLOBAL_POLICY_DISABLE_ENGINE_RESET; ads_blob_write(ads, policies.global_flags, global_flags); @@ -1004,7 +1004,7 @@ int xe_guc_ads_scheduler_policy_toggle_reset(struct xe_guc_ads *ads) policies->dpc_promote_time = ads_blob_read(ads, policies.dpc_promote_time); policies->max_num_work_items = ads_blob_read(ads, policies.max_num_work_items); policies->is_valid = 1; - if (xe->wedged.mode == 2) + if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) policies->global_flags |= GLOBAL_POLICY_DISABLE_ENGINE_RESET; else policies->global_flags &= ~GLOBAL_POLICY_DISABLE_ENGINE_RESET; diff --git a/drivers/gpu/drm/xe/xe_guc_capture.c b/drivers/gpu/drm/xe/xe_guc_capture.c index 2cda92f7b323..bdd700ac1e54 100644 --- a/drivers/gpu/drm/xe/xe_guc_capture.c +++ b/drivers/gpu/drm/xe/xe_guc_capture.c @@ -1889,7 +1889,14 @@ xe_guc_capture_get_matching_and_lock(struct xe_exec_queue *q) return NULL; xe = gt_to_xe(q->gt); - if (xe->wedged.mode >= 2 || !xe_device_uc_enabled(xe) || IS_SRIOV_VF(xe)) + + if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) + return NULL; + + if (!xe_device_uc_enabled(xe)) + return NULL; + + if (IS_SRIOV_VF(xe)) return NULL; ss = &xe->devcoredump.snapshot; diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index 7a4218f76024..45aa56b30a12 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -1339,8 +1339,9 @@ void xe_guc_submit_wedge(struct xe_guc *guc) err = devm_add_action_or_reset(guc_to_xe(guc)->drm.dev, guc_submit_wedged_fini, guc); if (err) { - xe_gt_err(gt, "Failed to register clean-up on wedged.mode=2; " - "Although device is wedged.\n"); + xe_gt_err(gt, "Failed to register clean-up in wedged.mode=%s; " + "Although device is wedged.\n", + xe_wedged_mode_to_string(XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)); return; } @@ -1355,7 +1356,7 @@ static bool guc_submit_hint_wedged(struct xe_guc *guc) { struct xe_device *xe = guc_to_xe(guc); - if (xe->wedged.mode != 2) + if (xe->wedged.mode != XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) return false; if (xe_device_wedged(xe)) diff --git a/drivers/gpu/drm/xe/xe_module.c b/drivers/gpu/drm/xe/xe_module.c index d08338fc3bc1..9934f90691fd 100644 --- a/drivers/gpu/drm/xe/xe_module.c +++ b/drivers/gpu/drm/xe/xe_module.c @@ -10,6 +10,7 @@ #include +#include "xe_device.h" #include "xe_drv.h" #include "xe_configfs.h" #include "xe_hw_fence.h" @@ -29,7 +30,8 @@ #define DEFAULT_FORCE_PROBE CONFIG_DRM_XE_FORCE_PROBE #define DEFAULT_MAX_VFS ~0 #define DEFAULT_MAX_VFS_STR "unlimited" -#define DEFAULT_WEDGED_MODE 1 +#define DEFAULT_WEDGED_MODE XE_WEDGED_MODE_DEFAULT +#define DEFAULT_WEDGED_MODE_STR XE_WEDGED_MODE_DEFAULT_STR #define DEFAULT_SVM_NOTIFIER_SIZE 512 struct xe_modparam xe_modparam = { @@ -88,10 +90,10 @@ MODULE_PARM_DESC(max_vfs, "[default=" DEFAULT_MAX_VFS_STR "])"); #endif -module_param_named_unsafe(wedged_mode, xe_modparam.wedged_mode, int, 0600); +module_param_named_unsafe(wedged_mode, xe_modparam.wedged_mode, uint, 0600); MODULE_PARM_DESC(wedged_mode, - "Module's default policy for the wedged mode (0=never, 1=upon-critical-errors, 2=upon-any-hang " - "[default=" __stringify(DEFAULT_WEDGED_MODE) "])"); + "Module's default policy for the wedged mode (0=never, 1=upon-critical-error, 2=upon-any-hang-no-reset " + "[default=" DEFAULT_WEDGED_MODE_STR "])"); static int xe_check_nomodeset(void) { diff --git a/drivers/gpu/drm/xe/xe_module.h b/drivers/gpu/drm/xe/xe_module.h index 5a3bfea8b7b4..1c75f38ca393 100644 --- a/drivers/gpu/drm/xe/xe_module.h +++ b/drivers/gpu/drm/xe/xe_module.h @@ -21,7 +21,7 @@ struct xe_modparam { #ifdef CONFIG_PCI_IOV unsigned int max_vfs; #endif - int wedged_mode; + unsigned int wedged_mode; u32 svm_notifier_size; }; -- cgit v1.2.3 From 0f13dead4e0385859f5c9c3625a19df116b389d3 Mon Sep 17 00:00:00 2001 From: Lukasz Laguna Date: Wed, 7 Jan 2026 18:47:39 +0100 Subject: drm/xe: Update wedged.mode only after successful reset policy change Previously, the driver's internal wedged.mode state was updated without verifying whether the corresponding engine reset policy update in GuC succeeded. This could leave the driver reporting a wedged.mode state that doesn't match the actual reset behavior programmed in GuC. With this change, the reset policy is updated first, and the driver's wedged.mode state is modified only if the policy update succeeds on all available GTs. This patch also introduces two functional improvements: - The policy is sent to GuC only when a change is required. An update is needed only when entering or leaving XE_WEDGED_MODE_UPON_ANY_HANG, because only in that case the reset policy changes. For example, switching between XE_WEDGED_MODE_UPON_CRITICAL_ERROR and XE_WEDGED_MODE_NEVER doesn't affect the reset policy, so there is no need to send the same value to GuC. - An inconsistent_reset flag is added to track cases where reset policy update succeeds only on a subset of GTs. If such inconsistency is detected, future wedged mode configuration will force a retry of the reset policy update to restore a consistent state across all GTs. Fixes: 6b8ef44cc0a9 ("drm/xe: Introduce the wedged_mode debugfs") Signed-off-by: Lukasz Laguna Link: https://patch.msgid.link/20260107174741.29163-3-lukasz.laguna@intel.com Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_debugfs.c | 70 +++++++++++++++++++++++++++++------- drivers/gpu/drm/xe/xe_device_types.h | 2 ++ drivers/gpu/drm/xe/xe_guc_ads.c | 14 ++++---- drivers/gpu/drm/xe/xe_guc_ads.h | 5 ++- 4 files changed, 71 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_debugfs.c b/drivers/gpu/drm/xe/xe_debugfs.c index db2afd60d8bc..844cfafe1ec7 100644 --- a/drivers/gpu/drm/xe/xe_debugfs.c +++ b/drivers/gpu/drm/xe/xe_debugfs.c @@ -254,14 +254,64 @@ static ssize_t wedged_mode_show(struct file *f, char __user *ubuf, return simple_read_from_buffer(ubuf, size, pos, buf, len); } +static int __wedged_mode_set_reset_policy(struct xe_gt *gt, enum xe_wedged_mode mode) +{ + bool enable_engine_reset; + int ret; + + enable_engine_reset = (mode != XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET); + ret = xe_guc_ads_scheduler_policy_toggle_reset(>->uc.guc.ads, + enable_engine_reset); + if (ret) + xe_gt_err(gt, "Failed to update GuC ADS scheduler policy (%pe)\n", ERR_PTR(ret)); + + return ret; +} + +static int wedged_mode_set_reset_policy(struct xe_device *xe, enum xe_wedged_mode mode) +{ + struct xe_gt *gt; + int ret; + u8 id; + + guard(xe_pm_runtime)(xe); + for_each_gt(gt, xe, id) { + ret = __wedged_mode_set_reset_policy(gt, mode); + if (ret) { + if (id > 0) { + xe->wedged.inconsistent_reset = true; + drm_err(&xe->drm, "Inconsistent reset policy state between GTs\n"); + } + return ret; + } + } + + xe->wedged.inconsistent_reset = false; + + return 0; +} + +static bool wedged_mode_needs_policy_update(struct xe_device *xe, enum xe_wedged_mode mode) +{ + if (xe->wedged.inconsistent_reset) + return true; + + if (xe->wedged.mode == mode) + return false; + + if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET || + mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) + return true; + + return false; +} + static ssize_t wedged_mode_set(struct file *f, const char __user *ubuf, size_t size, loff_t *pos) { struct xe_device *xe = file_inode(f)->i_private; - struct xe_gt *gt; u32 wedged_mode; ssize_t ret; - u8 id; ret = kstrtouint_from_user(ubuf, size, 0, &wedged_mode); if (ret) @@ -271,20 +321,14 @@ static ssize_t wedged_mode_set(struct file *f, const char __user *ubuf, if (ret) return ret; - if (xe->wedged.mode == wedged_mode) - return size; + if (wedged_mode_needs_policy_update(xe, wedged_mode)) { + ret = wedged_mode_set_reset_policy(xe, wedged_mode); + if (ret) + return ret; + } xe->wedged.mode = wedged_mode; - guard(xe_pm_runtime)(xe); - for_each_gt(gt, xe, id) { - ret = xe_guc_ads_scheduler_policy_toggle_reset(>->uc.guc.ads); - if (ret) { - xe_gt_err(gt, "Failed to update GuC ADS scheduler policy. GuC may still cause engine reset even with wedged_mode=2\n"); - return -EIO; - } - } - return size; } diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index d790129a06db..4dab3057f58d 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -648,6 +648,8 @@ struct xe_device { enum xe_wedged_mode mode; /** @wedged.method: Recovery method to be sent in the drm device wedged uevent */ unsigned long method; + /** @wedged.inconsistent_reset: Inconsistent reset policy state between GTs */ + bool inconsistent_reset; } wedged; /** @bo_device: Struct to control async free of BOs */ diff --git a/drivers/gpu/drm/xe/xe_guc_ads.c b/drivers/gpu/drm/xe/xe_guc_ads.c index 2b47e897d2ea..7e1cb6093de7 100644 --- a/drivers/gpu/drm/xe/xe_guc_ads.c +++ b/drivers/gpu/drm/xe/xe_guc_ads.c @@ -983,16 +983,17 @@ static int guc_ads_action_update_policies(struct xe_guc_ads *ads, u32 policy_off /** * xe_guc_ads_scheduler_policy_toggle_reset - Toggle reset policy * @ads: Additional data structures object + * @enable_engine_reset: true to enable engine resets, false otherwise * - * This function update the GuC's engine reset policy based on wedged.mode. + * This function update the GuC's engine reset policy. * * Return: 0 on success, and negative error code otherwise. */ -int xe_guc_ads_scheduler_policy_toggle_reset(struct xe_guc_ads *ads) +int xe_guc_ads_scheduler_policy_toggle_reset(struct xe_guc_ads *ads, + bool enable_engine_reset) { struct guc_policies *policies; struct xe_guc *guc = ads_to_guc(ads); - struct xe_device *xe = ads_to_xe(ads); CLASS(xe_guc_buf, buf)(&guc->buf, sizeof(*policies)); if (!xe_guc_buf_is_valid(buf)) @@ -1004,10 +1005,11 @@ int xe_guc_ads_scheduler_policy_toggle_reset(struct xe_guc_ads *ads) policies->dpc_promote_time = ads_blob_read(ads, policies.dpc_promote_time); policies->max_num_work_items = ads_blob_read(ads, policies.max_num_work_items); policies->is_valid = 1; - if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) - policies->global_flags |= GLOBAL_POLICY_DISABLE_ENGINE_RESET; - else + + if (enable_engine_reset) policies->global_flags &= ~GLOBAL_POLICY_DISABLE_ENGINE_RESET; + else + policies->global_flags |= GLOBAL_POLICY_DISABLE_ENGINE_RESET; return guc_ads_action_update_policies(ads, xe_guc_buf_flush(buf)); } diff --git a/drivers/gpu/drm/xe/xe_guc_ads.h b/drivers/gpu/drm/xe/xe_guc_ads.h index 2e6674c760ff..7a39f361cb17 100644 --- a/drivers/gpu/drm/xe/xe_guc_ads.h +++ b/drivers/gpu/drm/xe/xe_guc_ads.h @@ -6,6 +6,8 @@ #ifndef _XE_GUC_ADS_H_ #define _XE_GUC_ADS_H_ +#include + struct xe_guc_ads; int xe_guc_ads_init(struct xe_guc_ads *ads); @@ -13,6 +15,7 @@ int xe_guc_ads_init_post_hwconfig(struct xe_guc_ads *ads); void xe_guc_ads_populate(struct xe_guc_ads *ads); void xe_guc_ads_populate_minimal(struct xe_guc_ads *ads); void xe_guc_ads_populate_post_load(struct xe_guc_ads *ads); -int xe_guc_ads_scheduler_policy_toggle_reset(struct xe_guc_ads *ads); +int xe_guc_ads_scheduler_policy_toggle_reset(struct xe_guc_ads *ads, + bool enable_engine_reset); #endif -- cgit v1.2.3 From 43d78aca8ed01a643f198b831231a6231f52d9d5 Mon Sep 17 00:00:00 2001 From: Lukasz Laguna Date: Wed, 7 Jan 2026 18:47:40 +0100 Subject: drm/xe/vf: Disallow setting wedged mode to upon-any-hang In upon-any-hang (2) wedged mode, engine resets need to be disabled, which requires changing the GuC reset policy. VFs are not permitted to do that. Signed-off-by: Lukasz Laguna Reviewed-by: Michal Wajdeczko Link: https://patch.msgid.link/20260107174741.29163-4-lukasz.laguna@intel.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_device.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 62ec2e2d6436..d3431128670e 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -1387,6 +1387,11 @@ int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode) if (mode > XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) { drm_dbg(&xe->drm, "wedged_mode: invalid value (%u)\n", mode); return -EINVAL; + } else if (mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET && IS_SRIOV_VF(xe)) { + drm_dbg(&xe->drm, "wedged_mode: (%u) %s mode is not supported for %s\n", + mode, xe_wedged_mode_to_string(mode), + xe_sriov_mode_to_string(xe_device_sriov_mode(xe))); + return -EPERM; } return 0; -- cgit v1.2.3 From 96d45e34f8f9a459ae1a8d7a74638a96375d8597 Mon Sep 17 00:00:00 2001 From: Lukasz Laguna Date: Wed, 7 Jan 2026 18:47:41 +0100 Subject: drm/xe/pf: Allow upon-any-hang wedged mode only in debug config The GuC reset policy is global, so disabling it on PF can affect all running VFs. To avoid unintended side effects, restrict setting upon-any-hang (2) wedged mode on the PF to debug builds only. Signed-off-by: Lukasz Laguna Reviewed-by: Michal Wajdeczko Link: https://patch.msgid.link/20260107174741.29163-5-lukasz.laguna@intel.com Signed-off-by: Rodrigo Vivi --- 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 d3431128670e..e400ad5c9f9e 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -1387,7 +1387,8 @@ int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode) if (mode > XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) { drm_dbg(&xe->drm, "wedged_mode: invalid value (%u)\n", mode); return -EINVAL; - } else if (mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET && IS_SRIOV_VF(xe)) { + } else if (mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET && (IS_SRIOV_VF(xe) || + (IS_SRIOV_PF(xe) && !IS_ENABLED(CONFIG_DRM_XE_DEBUG)))) { drm_dbg(&xe->drm, "wedged_mode: (%u) %s mode is not supported for %s\n", mode, xe_wedged_mode_to_string(mode), xe_sriov_mode_to_string(xe_device_sriov_mode(xe))); -- cgit v1.2.3 From 351fa2ff098eccb2a98640d02f31319c3ceca0bc Mon Sep 17 00:00:00 2001 From: Osama Abdelkader Date: Wed, 24 Dec 2025 22:21:16 +0100 Subject: drm/xe: Add missing newlines to drm_warn messages The drm_warn() calls in the default cases of various switch statements in xe_vm.c were missing trailing newlines, which can cause log messages to be concatenated with subsequent output. Add '\n' to all affected messages. Signed-off-by: Osama Abdelkader Link: https://patch.msgid.link/20251224212116.59021-1-osama.abdelkader@gmail.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_vm.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index a07d8b53de66..2e07e60f47fa 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -2209,7 +2209,7 @@ static void print_op(struct xe_device *xe, struct drm_gpuva_op *op) (ULL)xe_vma_start(vma), (ULL)xe_vma_size(vma)); break; default: - drm_warn(&xe->drm, "NOT POSSIBLE"); + drm_warn(&xe->drm, "NOT POSSIBLE\n"); } } #else @@ -2312,7 +2312,7 @@ vm_bind_ioctl_ops_create(struct xe_vm *vm, struct xe_vma_ops *vops, xe_bo_unlock(bo); break; default: - drm_warn(&vm->xe->drm, "NOT POSSIBLE"); + drm_warn(&vm->xe->drm, "NOT POSSIBLE\n"); ops = ERR_PTR(-EINVAL); } if (IS_ERR(ops)) @@ -2584,7 +2584,7 @@ static int xe_vma_op_commit(struct xe_vm *vm, struct xe_vma_op *op) op->flags |= XE_VMA_OP_COMMITTED; break; default: - drm_warn(&vm->xe->drm, "NOT POSSIBLE"); + drm_warn(&vm->xe->drm, "NOT POSSIBLE\n"); } return err; @@ -2783,7 +2783,7 @@ static int vm_bind_ioctl_ops_parse(struct xe_vm *vm, struct drm_gpuva_ops *ops, break; default: - drm_warn(&vm->xe->drm, "NOT POSSIBLE"); + drm_warn(&vm->xe->drm, "NOT POSSIBLE\n"); } err = xe_vma_op_commit(vm, op); @@ -2845,7 +2845,7 @@ static void xe_vma_op_unwind(struct xe_vm *vm, struct xe_vma_op *op, /* Nothing to do */ break; default: - drm_warn(&vm->xe->drm, "NOT POSSIBLE"); + drm_warn(&vm->xe->drm, "NOT POSSIBLE\n"); } } @@ -3029,7 +3029,7 @@ static int op_lock_and_prep(struct drm_exec *exec, struct xe_vm *vm, break; } default: - drm_warn(&vm->xe->drm, "NOT POSSIBLE"); + drm_warn(&vm->xe->drm, "NOT POSSIBLE\n"); } return err; @@ -3268,7 +3268,7 @@ static void op_add_ufence(struct xe_vm *vm, struct xe_vma_op *op, vma_add_ufence(gpuva_to_vma(op->base.prefetch.va), ufence); break; default: - drm_warn(&vm->xe->drm, "NOT POSSIBLE"); + drm_warn(&vm->xe->drm, "NOT POSSIBLE\n"); } } -- cgit v1.2.3 From aa39abc08e77d66ebb0c8c9ec4cc8d38ded34dc9 Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Thu, 8 Jan 2026 19:01:48 +0100 Subject: drm/xe: fix WQ_MEM_RECLAIM passed as max_active to alloc_workqueue() Workqueue xe-ggtt-wq has been allocated using WQ_MEM_RECLAIM, but the flag has been passed as 3rd parameter (max_active) instead of 2nd (flags) creating the workqueue as per-cpu with max_active = 8 (the WQ_MEM_RECLAIM value). So change this by set WQ_MEM_RECLAIM as the 2nd parameter with a default max_active. Fixes: 60df57e496e4 ("drm/xe: Mark GGTT work queue with WQ_MEM_RECLAIM") Cc: stable@vger.kernel.org Signed-off-by: Marco Crivellari Reviewed-by: Matthew Brost Signed-off-by: Matthew Brost Link: https://patch.msgid.link/20260108180148.423062-1-marco.crivellari@suse.com --- drivers/gpu/drm/xe/xe_ggtt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_ggtt.c b/drivers/gpu/drm/xe/xe_ggtt.c index 48ab8b43fcd0..9e6b4e983542 100644 --- a/drivers/gpu/drm/xe/xe_ggtt.c +++ b/drivers/gpu/drm/xe/xe_ggtt.c @@ -322,7 +322,7 @@ int xe_ggtt_init_early(struct xe_ggtt *ggtt) else ggtt->pt_ops = &xelp_pt_ops; - ggtt->wq = alloc_workqueue("xe-ggtt-wq", 0, WQ_MEM_RECLAIM); + ggtt->wq = alloc_workqueue("xe-ggtt-wq", WQ_MEM_RECLAIM, 0); if (!ggtt->wq) return -ENOMEM; -- cgit v1.2.3 From 52cb4a595fbce93b1ef940f9d1097be9245d9179 Mon Sep 17 00:00:00 2001 From: Brian Nguyen Date: Wed, 7 Jan 2026 09:04:49 +0800 Subject: drm/xe: Remove debug comment in page reclaim Drop debug comment erronenously added in patch commit. Signed-off-by: Brian Nguyen Reviewed-by: Matthew Brost Signed-off-by: Matthew Brost Link: https://patch.msgid.link/20260107010447.4125005-7-brian3.nguyen@intel.com --- drivers/gpu/drm/xe/xe_page_reclaim.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_page_reclaim.c b/drivers/gpu/drm/xe/xe_page_reclaim.c index fd8c33761127..94d4608ebd74 100644 --- a/drivers/gpu/drm/xe/xe_page_reclaim.c +++ b/drivers/gpu/drm/xe/xe_page_reclaim.c @@ -108,7 +108,6 @@ void xe_page_reclaim_list_invalidate(struct xe_page_reclaim_list *prl) */ void xe_page_reclaim_list_init(struct xe_page_reclaim_list *prl) { - // xe_page_reclaim_list_invalidate(prl); prl->entries = NULL; prl->num_entries = 0; } -- cgit v1.2.3 From 7a0e86e3c9298c28f7bbbbb628bf1b7dd2de2916 Mon Sep 17 00:00:00 2001 From: Brian Nguyen Date: Wed, 7 Jan 2026 09:04:50 +0800 Subject: drm/xe: Add explicit abort page reclaim list PRLs could be invalidated to indicate its getting dropped from current scope but are still valid. So standardize calls and add abort to clearly define when an invalidation is a real abort and PRL should fallback. v3: - Update abort function to macro. (Matthew B) Signed-off-by: Brian Nguyen Reviewed-by: Matthew Brost Signed-off-by: Matthew Brost Link: https://patch.msgid.link/20260107010447.4125005-8-brian3.nguyen@intel.com --- drivers/gpu/drm/xe/xe_page_reclaim.h | 19 +++++++++++++++++++ drivers/gpu/drm/xe/xe_pt.c | 21 +++++++++------------ 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_page_reclaim.h b/drivers/gpu/drm/xe/xe_page_reclaim.h index a4f58e0ce9b4..12f861f357d8 100644 --- a/drivers/gpu/drm/xe/xe_page_reclaim.h +++ b/drivers/gpu/drm/xe/xe_page_reclaim.h @@ -19,6 +19,7 @@ struct xe_tlb_inval; struct xe_tlb_inval_fence; struct xe_tile; +struct xe_gt; struct xe_vma; struct xe_guc_page_reclaim_entry { @@ -75,6 +76,24 @@ struct drm_suballoc *xe_page_reclaim_create_prl_bo(struct xe_tlb_inval *tlb_inva struct xe_page_reclaim_list *prl, struct xe_tlb_inval_fence *fence); void xe_page_reclaim_list_invalidate(struct xe_page_reclaim_list *prl); + +/** + * xe_page_reclaim_list_abort() - Invalidate a PRL and log an abort reason + * @gt: GT owning the page reclaim request + * @prl: Page reclaim list to invalidate + * @fmt: format string for the log message with args + * + * Abort page reclaim process by invalidating PRL and doing any relevant logging. + */ +#define xe_page_reclaim_list_abort(gt, prl, fmt, ...) \ + do { \ + struct xe_gt *__gt = (gt); \ + struct xe_page_reclaim_list *__prl = (prl); \ + \ + xe_page_reclaim_list_invalidate(__prl); \ + vm_dbg(>_to_xe(__gt)->drm, "PRL aborted: " fmt, ##__VA_ARGS__); \ + } while (0) + void xe_page_reclaim_list_init(struct xe_page_reclaim_list *prl); int xe_page_reclaim_list_alloc_entries(struct xe_page_reclaim_list *prl); /** diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c index 6cd78bb2b652..2752a5a48a97 100644 --- a/drivers/gpu/drm/xe/xe_pt.c +++ b/drivers/gpu/drm/xe/xe_pt.c @@ -1618,10 +1618,9 @@ static int generate_reclaim_entry(struct xe_tile *tile, } else if (is_2m_pte(xe_child)) { reclamation_size = COMPUTE_RECLAIM_ADDRESS_MASK(SZ_2M); /* reclamation_size = 9 */ } else { - xe_page_reclaim_list_invalidate(prl); - vm_dbg(&tile_to_xe(tile)->drm, - "PRL invalidate: unsupported PTE level=%u pte=%#llx\n", - xe_child->level, pte); + xe_page_reclaim_list_abort(tile->primary_gt, prl, + "unsupported PTE level=%u pte=%#llx", + xe_child->level, pte); return -EINVAL; } @@ -1670,10 +1669,9 @@ static int xe_pt_stage_unbind_entry(struct xe_ptw *parent, pgoff_t offset, break; } else { /* overflow, mark as invalid */ - xe_page_reclaim_list_invalidate(xe_walk->prl); - vm_dbg(&xe->drm, - "PRL invalidate: overflow while adding pte=%#llx", - pte); + xe_page_reclaim_list_abort(xe_walk->tile->primary_gt, xe_walk->prl, + "overflow while adding pte=%#llx", + pte); break; } } @@ -1682,10 +1680,9 @@ static int xe_pt_stage_unbind_entry(struct xe_ptw *parent, pgoff_t offset, /* If aborting page walk early, invalidate PRL since PTE may be dropped from this abort */ if (xe_pt_check_kill(addr, next, level - 1, xe_child, action, walk) && xe_walk->prl && level > 1 && xe_child->base.children && xe_child->num_live != 0) { - xe_page_reclaim_list_invalidate(xe_walk->prl); - vm_dbg(&xe->drm, - "PRL invalidate: kill at level=%u addr=%#llx next=%#llx num_live=%u\n", - level, addr, next, xe_child->num_live); + xe_page_reclaim_list_abort(xe_walk->tile->primary_gt, xe_walk->prl, + "kill at level=%u addr=%#llx next=%#llx num_live=%u\n", + level, addr, next, xe_child->num_live); } return 0; -- cgit v1.2.3 From 83b914f972bb706536edd2b84230b9c1ce39f275 Mon Sep 17 00:00:00 2001 From: Brian Nguyen Date: Wed, 7 Jan 2026 09:04:51 +0800 Subject: drm/xe: Fix page reclaim entry handling for large pages For 64KB pages, XE_PTE_PS64 is defined for all consecutive 4KB pages and are all considered leaf nodes, so existing check was falsely adding multiple 64KB pages to PRL. For larger entries such as 2MB PDE, the check for pte->base.children is insufficient since this array is always defined for page directory, level 1 and above, so perform a check on the entry itself pointing to the correct page. For unmaps, if the range is properly covered by the page full directory, page walker may finish without walking to the leaf nodes. For example, a 1G range can be fully covered by 512 2MB pages if alignment allows. In this case, the page walker will walk until it reaches this corresponding directory which can correlate to the 1GB range. Page walker will simply complete its walk and the individual 2MB PDE leaves won't get accessed. In this case, PRL invalidation is also required, so add a check to see if pt entry cover the entire range since the walker will complete the walk. There are possible race conditions that will cause driver to read a pte that hasn't been written to yet. The 2 scenarios are: - Another issued TLB invalidation such as from userptr or MMU notifier. - Dependencies on original bind that has yet to be executed with an unbind on that job. The expectation is these race conditions are likely rare cases so simply perform a fallback to full PPC flush invalidation instead. v2: - Reword commit and updated zero-pte handling. (Matthew B) v3: - Rework if statement for abort case with additional comments. (Matthew B) Fixes: b912138df299 ("drm/xe: Create page reclaim list on unbind") Signed-off-by: Brian Nguyen Cc: Matthew Brost Reviewed-by: Matthew Brost Signed-off-by: Matthew Brost Link: https://patch.msgid.link/20260107010447.4125005-9-brian3.nguyen@intel.com --- drivers/gpu/drm/xe/xe_pt.c | 64 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c index 2752a5a48a97..a53944957be4 100644 --- a/drivers/gpu/drm/xe/xe_pt.c +++ b/drivers/gpu/drm/xe/xe_pt.c @@ -1576,12 +1576,6 @@ static bool xe_pt_check_kill(u64 addr, u64 next, unsigned int level, return false; } -/* Huge 2MB leaf lives directly in a level-1 table and has no children */ -static bool is_2m_pte(struct xe_pt *pte) -{ - return pte->level == 1 && !pte->base.children; -} - /* page_size = 2^(reclamation_size + XE_PTE_SHIFT) */ #define COMPUTE_RECLAIM_ADDRESS_MASK(page_size) \ ({ \ @@ -1594,7 +1588,8 @@ static int generate_reclaim_entry(struct xe_tile *tile, u64 pte, struct xe_pt *xe_child) { struct xe_guc_page_reclaim_entry *reclaim_entries = prl->entries; - u64 phys_page = (pte & XE_PTE_ADDR_MASK) >> XE_PTE_SHIFT; + u64 phys_addr = pte & XE_PTE_ADDR_MASK; + u64 phys_page = phys_addr >> XE_PTE_SHIFT; int num_entries = prl->num_entries; u32 reclamation_size; @@ -1613,10 +1608,13 @@ static int generate_reclaim_entry(struct xe_tile *tile, */ if (xe_child->level == 0 && !(pte & XE_PTE_PS64)) { 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) { reclamation_size = COMPUTE_RECLAIM_ADDRESS_MASK(SZ_64K); /* reclamation_size = 4 */ - } else if (is_2m_pte(xe_child)) { + xe_tile_assert(tile, phys_addr % SZ_64K == 0); + } else if (xe_child->level == 1 && pte & XE_PDE_PS_2M) { reclamation_size = COMPUTE_RECLAIM_ADDRESS_MASK(SZ_2M); /* reclamation_size = 9 */ + xe_tile_assert(tile, phys_addr % SZ_2M == 0); } else { xe_page_reclaim_list_abort(tile->primary_gt, prl, "unsupported PTE level=%u pte=%#llx", @@ -1647,20 +1645,40 @@ static int xe_pt_stage_unbind_entry(struct xe_ptw *parent, pgoff_t offset, 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); + 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) && - !xe_child->base.children) { + (!xe_child->base.children || !xe_child->base.children[first])) { struct iosys_map *leaf_map = &xe_child->bo->vmap; - pgoff_t first = xe_pt_offset(addr, 0, walk); - pgoff_t count = xe_pt_num_entries(addr, next, 0, walk); + pgoff_t count = xe_pt_num_entries(addr, next, xe_child->level, walk); for (pgoff_t i = 0; i < count; i++) { u64 pte = xe_map_rd(xe, leaf_map, (first + i) * sizeof(u64), u64); int ret; + /* + * 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); + break; + } + + /* Ensure it is a defined page */ + xe_tile_assert(xe_walk->tile, + xe_child->level == 0 || + (pte & (XE_PTE_PS64 | 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, @@ -1677,12 +1695,24 @@ static int xe_pt_stage_unbind_entry(struct xe_ptw *parent, pgoff_t offset, } } - /* If aborting page walk early, invalidate PRL since PTE may be dropped from this abort */ - if (xe_pt_check_kill(addr, next, level - 1, xe_child, action, walk) && - xe_walk->prl && level > 1 && xe_child->base.children && xe_child->num_live != 0) { - xe_page_reclaim_list_abort(xe_walk->tile->primary_gt, xe_walk->prl, - "kill at level=%u addr=%#llx next=%#llx num_live=%u\n", - level, addr, next, xe_child->num_live); + killed = xe_pt_check_kill(addr, next, level - 1, xe_child, action, walk); + + /* + * Verify PRL is active and if entry is not a leaf pte (base.children conditions), + * there is a potential need to invalidate the PRL if any PTE (num_live) are dropped. + */ + if (xe_walk->prl && level > 1 && xe_child->num_live && + xe_child->base.children && xe_child->base.children[first]) { + bool covered = xe_pt_covers(addr, next, xe_child->level, &xe_walk->base); + + /* + * If aborting page walk early (kill) or page walk completes the full range + * we need to invalidate the PRL. + */ + if (killed || covered) + xe_page_reclaim_list_abort(xe_walk->tile->primary_gt, xe_walk->prl, + "kill at level=%u addr=%#llx next=%#llx num_live=%u", + level, addr, next, xe_child->num_live); } return 0; -- cgit v1.2.3 From 2e08feebe0353320651013c5bdab58c2a19a716b Mon Sep 17 00:00:00 2001 From: Brian Nguyen Date: Wed, 7 Jan 2026 09:04:52 +0800 Subject: drm/xe: Add page reclamation related stats Add page reclaim list (PRL) related stats to GT stats to assist in debugging and tuning of page reclaim related actions. Include counters of page sizes added to PRL and if PRL action is issued. v2: - Add PRL_ABORTED_COUNT stats and corresponding changes. (Matthew B) Signed-off-by: Brian Nguyen Cc: Matthew Brost Reviewed-by: Matthew Brost Signed-off-by: Matthew Brost Link: https://patch.msgid.link/20260107010447.4125005-10-brian3.nguyen@intel.com --- drivers/gpu/drm/xe/xe_gt_stats.c | 5 +++++ drivers/gpu/drm/xe/xe_gt_stats_types.h | 5 +++++ drivers/gpu/drm/xe/xe_guc_tlb_inval.c | 3 +++ drivers/gpu/drm/xe/xe_page_reclaim.c | 1 + drivers/gpu/drm/xe/xe_page_reclaim.h | 1 + drivers/gpu/drm/xe/xe_pt.c | 5 +++++ 6 files changed, 20 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_gt_stats.c b/drivers/gpu/drm/xe/xe_gt_stats.c index fb2904bd0abd..8294bcd40310 100644 --- a/drivers/gpu/drm/xe/xe_gt_stats.c +++ b/drivers/gpu/drm/xe/xe_gt_stats.c @@ -76,6 +76,11 @@ static const char *const stat_description[__XE_GT_STATS_NUM_IDS] = { "hw_engine_group_suspend_lr_queue_us"), DEF_STAT_STR(HW_ENGINE_GROUP_WAIT_DMA_QUEUE_US, "hw_engine_group_wait_dma_queue_us"), + DEF_STAT_STR(PRL_4K_ENTRY_COUNT, "prl_4k_entry_count"), + DEF_STAT_STR(PRL_64K_ENTRY_COUNT, "prl_64k_entry_count"), + DEF_STAT_STR(PRL_2M_ENTRY_COUNT, "prl_2m_entry_count"), + DEF_STAT_STR(PRL_ISSUED_COUNT, "prl_issued_count"), + DEF_STAT_STR(PRL_ABORTED_COUNT, "prl_aborted_count"), }; /** diff --git a/drivers/gpu/drm/xe/xe_gt_stats_types.h b/drivers/gpu/drm/xe/xe_gt_stats_types.h index b92d013091d5..b8accdbc54eb 100644 --- a/drivers/gpu/drm/xe/xe_gt_stats_types.h +++ b/drivers/gpu/drm/xe/xe_gt_stats_types.h @@ -49,6 +49,11 @@ enum xe_gt_stats_id { XE_GT_STATS_ID_HW_ENGINE_GROUP_WAIT_DMA_QUEUE_COUNT, XE_GT_STATS_ID_HW_ENGINE_GROUP_SUSPEND_LR_QUEUE_US, XE_GT_STATS_ID_HW_ENGINE_GROUP_WAIT_DMA_QUEUE_US, + XE_GT_STATS_ID_PRL_4K_ENTRY_COUNT, + XE_GT_STATS_ID_PRL_64K_ENTRY_COUNT, + XE_GT_STATS_ID_PRL_2M_ENTRY_COUNT, + XE_GT_STATS_ID_PRL_ISSUED_COUNT, + XE_GT_STATS_ID_PRL_ABORTED_COUNT, /* must be the last entry */ __XE_GT_STATS_NUM_IDS, }; diff --git a/drivers/gpu/drm/xe/xe_guc_tlb_inval.c b/drivers/gpu/drm/xe/xe_guc_tlb_inval.c index 6532a88d51e2..774467befbb9 100644 --- a/drivers/gpu/drm/xe/xe_guc_tlb_inval.c +++ b/drivers/gpu/drm/xe/xe_guc_tlb_inval.c @@ -97,6 +97,7 @@ static int send_tlb_inval_ggtt(struct xe_tlb_inval *tlb_inval, u32 seqno) static int send_page_reclaim(struct xe_guc *guc, u32 seqno, u64 gpu_addr) { + struct xe_gt *gt = guc_to_gt(guc); u32 action[] = { XE_GUC_ACTION_PAGE_RECLAMATION, seqno, @@ -104,6 +105,8 @@ static int send_page_reclaim(struct xe_guc *guc, u32 seqno, upper_32_bits(gpu_addr), }; + xe_gt_stats_incr(gt, XE_GT_STATS_ID_PRL_ISSUED_COUNT, 1); + return xe_guc_ct_send(&guc->ct, action, ARRAY_SIZE(action), G2H_LEN_DW_PAGE_RECLAMATION, 1); } diff --git a/drivers/gpu/drm/xe/xe_page_reclaim.c b/drivers/gpu/drm/xe/xe_page_reclaim.c index 94d4608ebd74..a8f35919a9da 100644 --- a/drivers/gpu/drm/xe/xe_page_reclaim.c +++ b/drivers/gpu/drm/xe/xe_page_reclaim.c @@ -12,6 +12,7 @@ #include "regs/xe_gt_regs.h" #include "xe_assert.h" +#include "xe_gt_stats.h" #include "xe_macros.h" #include "xe_mmio.h" #include "xe_pat.h" diff --git a/drivers/gpu/drm/xe/xe_page_reclaim.h b/drivers/gpu/drm/xe/xe_page_reclaim.h index 12f861f357d8..3dd103e37beb 100644 --- a/drivers/gpu/drm/xe/xe_page_reclaim.h +++ b/drivers/gpu/drm/xe/xe_page_reclaim.h @@ -91,6 +91,7 @@ void xe_page_reclaim_list_invalidate(struct xe_page_reclaim_list *prl); struct xe_page_reclaim_list *__prl = (prl); \ \ xe_page_reclaim_list_invalidate(__prl); \ + xe_gt_stats_incr(__gt, XE_GT_STATS_ID_PRL_ABORTED_COUNT, 1); \ vm_dbg(>_to_xe(__gt)->drm, "PRL aborted: " fmt, ##__VA_ARGS__); \ } while (0) diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c index a53944957be4..6703a7049227 100644 --- a/drivers/gpu/drm/xe/xe_pt.c +++ b/drivers/gpu/drm/xe/xe_pt.c @@ -11,6 +11,7 @@ #include "xe_drm_client.h" #include "xe_exec_queue.h" #include "xe_gt.h" +#include "xe_gt_stats.h" #include "xe_migrate.h" #include "xe_page_reclaim.h" #include "xe_pt_types.h" @@ -1587,6 +1588,7 @@ 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; u64 phys_page = phys_addr >> XE_PTE_SHIFT; @@ -1607,12 +1609,15 @@ static int generate_reclaim_entry(struct xe_tile *tile, * 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) { + 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 { -- cgit v1.2.3 From 4cdcfa64b6032ec68cdaa6c424b3b293cf7ff45c Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 7 Jan 2026 17:53:57 +0200 Subject: drm/xe/guc: fix struct guc_lfd_file_header kernel-doc Fix kernel-doc warnings on struct guc_lfd_file_header: Warning: ../drivers/gpu/drm/xe/abi/guc_lfd_abi.h:168 expecting prototype for struct guc_logfile_header. Prototype was for struct guc_lfd_file_header instead Fixes: 7eeb0e5408bd ("drm/xe/guc: Add LFD related abi definitions") Cc: Zhanjun Dong Cc: Julia Filipchuk Cc: Ashutosh Dixit Reviewed-by: Zhanjun Dong Reviewed-by: Matt Roper Link: https://patch.msgid.link/20260107155401.2379127-1-jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/xe/abi/guc_lfd_abi.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/abi/guc_lfd_abi.h b/drivers/gpu/drm/xe/abi/guc_lfd_abi.h index b6ed20d5b508..5c48459f365f 100644 --- a/drivers/gpu/drm/xe/abi/guc_lfd_abi.h +++ b/drivers/gpu/drm/xe/abi/guc_lfd_abi.h @@ -148,7 +148,7 @@ struct guc_lfd_data_os_info { } __packed; /** - * struct guc_logfile_header - Header of GuC Log Streaming-LFD-File Format. + * struct guc_lfd_file_header - Header of GuC Log Streaming-LFD-File Format. * This structure encapsulates the layout of the guc-log-file format */ struct guc_lfd_file_header { @@ -163,8 +163,7 @@ struct guc_lfd_file_header { #define GUC_LFD_FILE_HEADER_VERSION_MASK_MAJOR GENMASK(31, 16) #define GUC_LFD_FILE_HEADER_VERSION_MASK_MINOR GENMASK(15, 0) - /** @stream: A stream of one or more guc_lfd_data LFD blocks - */ + /** @stream: A stream of one or more guc_lfd_data LFD blocks */ u32 stream[]; } __packed; -- cgit v1.2.3 From 44393331c79f5df14c1ff25f4a355f439a2dc8a2 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 7 Jan 2026 17:53:58 +0200 Subject: drm/xe/vf: fix struct xe_gt_sriov_vf_migration kernel-doc Fix kernel-doc warnings on struct xe_gt_sriov_vf_migration: Warning: ../drivers/gpu/drm/xe/xe_gt_sriov_vf_types.h:47 cannot understand function prototype: 'struct xe_gt_sriov_vf_migration' Fixes: e1d2e2d878bf ("drm/xe/vf: Add xe_gt_recovery_pending helper") Cc: Matthew Brost Cc: Michal Wajdeczko Cc: Tomasz Lis Reviewed-by: Matt Roper Link: https://patch.msgid.link/20260107155401.2379127-2-jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/xe/xe_gt_sriov_vf_types.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_vf_types.h b/drivers/gpu/drm/xe/xe_gt_sriov_vf_types.h index 9a6b5672d569..4ef881b9b662 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_vf_types.h +++ b/drivers/gpu/drm/xe/xe_gt_sriov_vf_types.h @@ -43,10 +43,10 @@ struct xe_gt_sriov_vf_runtime { }; /** - * xe_gt_sriov_vf_migration - VF migration data. + * struct xe_gt_sriov_vf_migration - VF migration data. */ struct xe_gt_sriov_vf_migration { - /** @migration: VF migration recovery worker */ + /** @worker: VF migration recovery worker */ struct work_struct worker; /** @lock: Protects recovery_queued, teardown */ spinlock_t lock; -- cgit v1.2.3 From a857e6102970c7bd8f2db967fe02d76741179d14 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 7 Jan 2026 17:53:59 +0200 Subject: drm/xe/xe_late_bind_fw: fix enum xe_late_bind_fw_id kernel-doc Fix kernel-doc warnings on enum xe_late_bind_fw_id: Warning: ../drivers/gpu/drm/xe/xe_late_bind_fw_types.h:19 cannot understand function prototype: 'enum xe_late_bind_fw_id' Fixes: 45832bf9c10f ("drm/xe/xe_late_bind_fw: Initialize late binding firmware") Cc: Badal Nilawar Cc: Daniele Ceraolo Spurio Cc: Rodrigo Vivi Reviewed-by: Badal Nilawar Link: https://patch.msgid.link/20260107155401.2379127-3-jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/xe/xe_late_bind_fw_types.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_late_bind_fw_types.h b/drivers/gpu/drm/xe/xe_late_bind_fw_types.h index 0f5da89ce98b..2a8a985c37e7 100644 --- a/drivers/gpu/drm/xe/xe_late_bind_fw_types.h +++ b/drivers/gpu/drm/xe/xe_late_bind_fw_types.h @@ -15,10 +15,12 @@ #define XE_LB_MAX_PAYLOAD_SIZE SZ_4K /** - * xe_late_bind_fw_id - enum to determine late binding fw index + * enum xe_late_bind_fw_id - enum to determine late binding fw index */ enum xe_late_bind_fw_id { + /** @XE_LB_FW_FAN_CONTROL: Fan control */ XE_LB_FW_FAN_CONTROL = 0, + /** @XE_LB_FW_MAX_ID: Number of IDs */ XE_LB_FW_MAX_ID }; -- cgit v1.2.3 From b3a7767989e6519127ac5e0cde682c50ad587f3b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 7 Jan 2026 17:54:00 +0200 Subject: drm/xe/vm: fix xe_vm_validation_exec() kernel-doc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix kernel-doc warnings on xe_vm_validation_exec(): Warning: ../drivers/gpu/drm/xe/xe_vm.h:392 expecting prototype for xe_vm_set_validation_exec(). Prototype was for xe_vm_validation_exec() instead Fixes: 0131514f9789 ("drm/xe: Pass down drm_exec context to validation") Cc: Thomas Hellström Cc: Matthew Brost Reviewed-by: Matt Roper Link: https://patch.msgid.link/20260107155401.2379127-4-jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/xe/xe_vm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_vm.h b/drivers/gpu/drm/xe/xe_vm.h index 7d11ca47d73e..6cc98df47291 100644 --- a/drivers/gpu/drm/xe/xe_vm.h +++ b/drivers/gpu/drm/xe/xe_vm.h @@ -382,7 +382,7 @@ static inline void xe_vm_set_validation_exec(struct xe_vm *vm, struct drm_exec * } /** - * xe_vm_set_validation_exec() - Accessor to read the drm_exec object + * xe_vm_validation_exec() - Accessor to read the drm_exec object * @vm: The vm we want to register a drm_exec object with. * * Return: The drm_exec object used to lock the vm's resv. The value -- cgit v1.2.3 From 72f654f4247fbf0b0ddb9092052531deb6fb895b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 7 Jan 2026 17:54:01 +0200 Subject: drm/xe: improve header check Improve header check: Remove unused -DHDRTEST. Include the header twice to check for include guards. Run kernel-doc on the header. Reviewed-by: Matt Roper Link: https://patch.msgid.link/20260107155401.2379127-5-jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/xe/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 8dcc85cb8d42..3a6a707638b5 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -370,7 +370,8 @@ always-$(CONFIG_DRM_XE_WERROR) += \ $(patsubst %.h,%.hdrtest, $(shell cd $(src) && find * -name '*.h' $(hdrtest_find_args))) quiet_cmd_hdrtest = HDRTEST $(patsubst %.hdrtest,%.h,$@) - cmd_hdrtest = $(CC) -DHDRTEST $(filter-out $(CFLAGS_GCOV), $(c_flags)) -S -o /dev/null -x c /dev/null -include $<; touch $@ + cmd_hdrtest = $(CC) $(filter-out $(CFLAGS_GCOV), $(c_flags)) -S -o /dev/null -x c /dev/null -include $< -include $<; \ + $(srctree)/scripts/kernel-doc -none -Werror $<; touch $@ $(obj)/%.hdrtest: $(src)/%.h FORCE $(call if_changed_dep,hdrtest) -- cgit v1.2.3 From 98466abe4ed949d6ae40bf3e2b1739e9ddd74af9 Mon Sep 17 00:00:00 2001 From: Xin Wang Date: Fri, 9 Jan 2026 09:30:06 +0000 Subject: drm/xe: Allow compressible surfaces to be 1-way coherent Previously, compressible surfaces were required to be non-coherent (allocated as WC) because compression and coherency were mutually exclusive. Starting with Xe3, hardware supports combining compression with 1-way coherency, allowing compressible surfaces to be allocated as WB memory. This provides applications with more efficient memory allocation by avoiding WC allocation overhead that can cause system stuttering and memory management challenges. The implementation adds support for compressed+coherent PAT entry for the xe3_lpg devices and updates the driver logic to handle the new compression capabilities. v2: (Matthew Auld) - Improved error handling with XE_IOCTL_DBG() - Enhanced documentation and comments - Fixed xe_bo_needs_ccs_pages() outdated compression assumptions v3: - Improve WB compression support detection by checking PAT table instead of version check v4: - Add XE_CACHE_WB_COMPRESSION, which simplifies the logic. v5: - Use U16_MAX for the invalid PAT index. (Matthew Auld) Bspec: 71582, 59361, 59399 Cc: Matthew Auld Cc: Matt Roper Signed-off-by: Xin Wang Reviewed-by: Matthew Auld Link: https://patch.msgid.link/20260109093007.546784-1-x.wang@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/regs/xe_gt_regs.h | 6 +++++ drivers/gpu/drm/xe/xe_bo.c | 17 ++++++------ drivers/gpu/drm/xe/xe_gt.c | 32 ++++++++++++++++++++++ drivers/gpu/drm/xe/xe_pat.c | 52 +++++++++++++++++++++++++++++++----- drivers/gpu/drm/xe/xe_pat.h | 2 ++ drivers/gpu/drm/xe/xe_pt_types.h | 1 + drivers/gpu/drm/xe/xe_vm.c | 13 +++++++++ 7 files changed, 109 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h index 93643da57428..24fc64fc832e 100644 --- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h +++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h @@ -89,6 +89,7 @@ #define UNIFIED_COMPRESSION_FORMAT REG_GENMASK(3, 0) #define XE2_GAMREQSTRM_CTRL XE_REG_MCR(0x4194) +#define EN_CMP_1WCOH REG_BIT(15) #define CG_DIS_CNTLBUS REG_BIT(6) #define CCS_AUX_INV XE_REG(0x4208) @@ -101,6 +102,11 @@ #define XE2_LMEM_CFG XE_REG(0x48b0) +#define XE2_GAMWALK_CTRL 0x47e4 +#define XE2_GAMWALK_CTRL_MEDIA XE_REG(XE2_GAMWALK_CTRL + MEDIA_GT_GSI_OFFSET) +#define XE2_GAMWALK_CTRL_3D XE_REG_MCR(XE2_GAMWALK_CTRL) +#define EN_CMP_1WCOH_GW REG_BIT(14) + #define XEHP_FLAT_CCS_BASE_ADDR XE_REG_MCR(0x4910) #define XEHP_FLAT_CCS_PTR REG_GENMASK(31, 8) diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index 6ab52fa397e3..408c74216fdf 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -29,6 +29,7 @@ #include "xe_gt.h" #include "xe_map.h" #include "xe_migrate.h" +#include "xe_pat.h" #include "xe_pm.h" #include "xe_preempt_fence.h" #include "xe_pxp.h" @@ -3522,16 +3523,16 @@ bool xe_bo_needs_ccs_pages(struct xe_bo *bo) if (IS_DGFX(xe) && (bo->flags & XE_BO_FLAG_SYSTEM)) return false; + /* Check if userspace explicitly requested no compression */ + if (bo->flags & XE_BO_FLAG_NO_COMPRESSION) + return false; + /* - * Compression implies coh_none, therefore we know for sure that WB - * memory can't currently use compression, which is likely one of the - * common cases. - * Additionally, userspace may explicitly request no compression via the - * DRM_XE_GEM_CREATE_FLAG_NO_COMPRESSION flag, which should also disable - * CCS usage. + * For WB (Write-Back) CPU caching mode, check if the device + * supports WB compression with coherency. */ - if (bo->cpu_caching == DRM_XE_GEM_CPU_CACHING_WB || - bo->flags & XE_BO_FLAG_NO_COMPRESSION) + if (bo->cpu_caching == DRM_XE_GEM_CPU_CACHING_WB && + xe->pat.idx[XE_CACHE_WB_COMPRESSION] == XE_PAT_INVALID_IDX) return false; return true; diff --git a/drivers/gpu/drm/xe/xe_gt.c b/drivers/gpu/drm/xe/xe_gt.c index 313ce83ab0e5..04dbf995a18b 100644 --- a/drivers/gpu/drm/xe/xe_gt.c +++ b/drivers/gpu/drm/xe/xe_gt.c @@ -140,6 +140,36 @@ static void xe_gt_disable_host_l2_vram(struct xe_gt *gt) xe_gt_mcr_multicast_write(gt, XE2_GAMREQSTRM_CTRL, reg); } +static void xe_gt_enable_comp_1wcoh(struct xe_gt *gt) +{ + struct xe_device *xe = gt_to_xe(gt); + unsigned int fw_ref; + u32 reg; + + if (IS_SRIOV_VF(xe)) + return; + + if (GRAPHICS_VER(xe) >= 30 && xe->info.has_flat_ccs) { + fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); + if (!fw_ref) + return; + + reg = xe_gt_mcr_unicast_read_any(gt, XE2_GAMREQSTRM_CTRL); + reg |= EN_CMP_1WCOH; + xe_gt_mcr_multicast_write(gt, XE2_GAMREQSTRM_CTRL, reg); + + if (xe_gt_is_media_type(gt)) { + xe_mmio_rmw32(>->mmio, XE2_GAMWALK_CTRL_MEDIA, 0, EN_CMP_1WCOH_GW); + } else { + reg = xe_gt_mcr_unicast_read_any(gt, XE2_GAMWALK_CTRL_3D); + reg |= EN_CMP_1WCOH_GW; + xe_gt_mcr_multicast_write(gt, XE2_GAMWALK_CTRL_3D, reg); + } + + xe_force_wake_put(gt_to_fw(gt), fw_ref); + } +} + static void gt_reset_worker(struct work_struct *w); static int emit_job_sync(struct xe_exec_queue *q, struct xe_bb *bb, @@ -466,6 +496,7 @@ static int gt_init_with_gt_forcewake(struct xe_gt *gt) xe_gt_topology_init(gt); xe_gt_mcr_init(gt); xe_gt_enable_host_l2_vram(gt); + xe_gt_enable_comp_1wcoh(gt); if (xe_gt_is_main_type(gt)) { err = xe_ggtt_init(gt_to_tile(gt)->mem.ggtt); @@ -745,6 +776,7 @@ static int do_gt_restart(struct xe_gt *gt) xe_pat_init(gt); xe_gt_enable_host_l2_vram(gt); + xe_gt_enable_comp_1wcoh(gt); xe_gt_mcr_set_implicit_defaults(gt); xe_reg_sr_apply_mmio(>->reg_sr, gt); diff --git a/drivers/gpu/drm/xe/xe_pat.c b/drivers/gpu/drm/xe/xe_pat.c index 2c3375e0250b..14d0dce5190a 100644 --- a/drivers/gpu/drm/xe/xe_pat.c +++ b/drivers/gpu/drm/xe/xe_pat.c @@ -132,9 +132,10 @@ static const struct xe_pat_table_entry xelpg_pat_table[] = { * in the table. * * Note: There is an implicit assumption in the driver that compression and - * coh_1way+ are mutually exclusive. If this is ever not true then userptr - * and imported dma-buf from external device will have uncleared ccs state. See - * also xe_bo_needs_ccs_pages(). + * coh_1way+ are mutually exclusive for platforms prior to Xe3. Starting + * with Xe3, compression can be combined with coherency. If using compression + * with coherency, userptr and imported dma-buf from external device will + * have uncleared ccs state. See also xe_bo_needs_ccs_pages(). */ #define XE2_PAT(no_promote, comp_en, l3clos, l3_policy, l4_policy, __coh_mode) \ { \ @@ -144,8 +145,7 @@ static const struct xe_pat_table_entry xelpg_pat_table[] = { REG_FIELD_PREP(XE2_L3_POLICY, l3_policy) | \ REG_FIELD_PREP(XE2_L4_POLICY, l4_policy) | \ REG_FIELD_PREP(XE2_COH_MODE, __coh_mode), \ - .coh_mode = (BUILD_BUG_ON_ZERO(__coh_mode && comp_en) || __coh_mode) ? \ - XE_COH_AT_LEAST_1WAY : XE_COH_NONE, \ + .coh_mode = __coh_mode ? XE_COH_AT_LEAST_1WAY : XE_COH_NONE, \ .valid = 1 \ } @@ -181,6 +181,38 @@ static const struct xe_pat_table_entry xe2_pat_table[] = { [31] = XE2_PAT( 0, 0, 3, 0, 3, 3 ), }; +static const struct xe_pat_table_entry xe3_lpg_pat_table[] = { + [ 0] = XE2_PAT( 0, 0, 0, 0, 3, 0 ), + [ 1] = XE2_PAT( 0, 0, 0, 0, 3, 2 ), + [ 2] = XE2_PAT( 0, 0, 0, 0, 3, 3 ), + [ 3] = XE2_PAT( 0, 0, 0, 3, 3, 0 ), + [ 4] = XE2_PAT( 0, 0, 0, 3, 0, 2 ), + [ 5] = XE2_PAT( 0, 0, 0, 3, 3, 2 ), + [ 6] = XE2_PAT( 1, 0, 0, 1, 3, 0 ), + [ 7] = XE2_PAT( 0, 0, 0, 3, 0, 3 ), + [ 8] = XE2_PAT( 0, 0, 0, 3, 0, 0 ), + [ 9] = XE2_PAT( 0, 1, 0, 0, 3, 0 ), + [10] = XE2_PAT( 0, 1, 0, 3, 0, 0 ), + [11] = XE2_PAT( 1, 1, 0, 1, 3, 0 ), + [12] = XE2_PAT( 0, 1, 0, 3, 3, 0 ), + [13] = XE2_PAT( 0, 0, 0, 0, 0, 0 ), + [14] = XE2_PAT( 0, 1, 0, 0, 0, 0 ), + [15] = XE2_PAT( 1, 1, 0, 1, 1, 0 ), + [16] = XE2_PAT( 0, 1, 0, 0, 3, 2 ), + /* 17..19 are reserved; leave set to all 0's */ + [20] = XE2_PAT( 0, 0, 1, 0, 3, 0 ), + [21] = XE2_PAT( 0, 1, 1, 0, 3, 0 ), + [22] = XE2_PAT( 0, 0, 1, 0, 3, 2 ), + [23] = XE2_PAT( 0, 0, 1, 0, 3, 3 ), + [24] = XE2_PAT( 0, 0, 2, 0, 3, 0 ), + [25] = XE2_PAT( 0, 1, 2, 0, 3, 0 ), + [26] = XE2_PAT( 0, 0, 2, 0, 3, 2 ), + [27] = XE2_PAT( 0, 0, 2, 0, 3, 3 ), + [28] = XE2_PAT( 0, 0, 3, 0, 3, 0 ), + [29] = XE2_PAT( 0, 1, 3, 0, 3, 0 ), + [30] = XE2_PAT( 0, 0, 3, 0, 3, 2 ), + [31] = XE2_PAT( 0, 0, 3, 0, 3, 3 ), +}; /* Special PAT values programmed outside the main table */ static const struct xe_pat_table_entry xe2_pat_ats = XE2_PAT( 0, 0, 0, 0, 3, 3 ); static const struct xe_pat_table_entry xe2_pat_pta = XE2_PAT( 0, 0, 0, 0, 3, 0 ); @@ -490,6 +522,7 @@ static const struct xe_pat_ops xe3p_xpc_pat_ops = { void xe_pat_init_early(struct xe_device *xe) { + xe->pat.idx[XE_CACHE_WB_COMPRESSION] = XE_PAT_INVALID_IDX; if (GRAPHICS_VERx100(xe) == 3511) { xe->pat.ops = &xe3p_xpc_pat_ops; xe->pat.table = xe3p_xpc_pat_table; @@ -501,7 +534,12 @@ void xe_pat_init_early(struct xe_device *xe) xe->pat.idx[XE_CACHE_WB] = 2; } else if (GRAPHICS_VER(xe) == 30 || GRAPHICS_VER(xe) == 20) { xe->pat.ops = &xe2_pat_ops; - xe->pat.table = xe2_pat_table; + if (GRAPHICS_VER(xe) == 30) { + xe->pat.table = xe3_lpg_pat_table; + xe->pat.idx[XE_CACHE_WB_COMPRESSION] = 16; + } else { + xe->pat.table = xe2_pat_table; + } xe->pat.pat_ats = &xe2_pat_ats; if (IS_DGFX(xe)) xe->pat.pat_pta = &xe2_pat_pta; @@ -658,6 +696,8 @@ int xe_pat_dump_sw_config(struct xe_gt *gt, struct drm_printer *p) if (GRAPHICS_VER(xe) >= 20) { drm_printf(p, "IDX[XE_CACHE_NONE_COMPRESSION] = %d\n", xe->pat.idx[XE_CACHE_NONE_COMPRESSION]); + drm_printf(p, "IDX[XE_CACHE_WB_COMPRESSION] = %d\n", + xe->pat.idx[XE_CACHE_WB_COMPRESSION]); } return 0; diff --git a/drivers/gpu/drm/xe/xe_pat.h b/drivers/gpu/drm/xe/xe_pat.h index d5dadfb7f924..c7e2a53d8cee 100644 --- a/drivers/gpu/drm/xe/xe_pat.h +++ b/drivers/gpu/drm/xe/xe_pat.h @@ -12,6 +12,8 @@ struct drm_printer; struct xe_device; struct xe_gt; +#define XE_PAT_INVALID_IDX U16_MAX + /** * struct xe_pat_table_entry - The pat_index encoding and other meta information. */ diff --git a/drivers/gpu/drm/xe/xe_pt_types.h b/drivers/gpu/drm/xe/xe_pt_types.h index 88fabf8e2655..84b51d3762a4 100644 --- a/drivers/gpu/drm/xe/xe_pt_types.h +++ b/drivers/gpu/drm/xe/xe_pt_types.h @@ -20,6 +20,7 @@ enum xe_cache_level { XE_CACHE_WT, XE_CACHE_WB, XE_CACHE_NONE_COMPRESSION, /*UC + COH_NONE + COMPRESSION */ + XE_CACHE_WB_COMPRESSION, __XE_CACHE_LEVEL_COUNT, }; diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index 2e07e60f47fa..001bc36da5ef 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -3405,6 +3405,7 @@ static int vm_bind_ioctl_check_args(struct xe_device *xe, struct xe_vm *vm, DRM_XE_VM_BIND_FLAG_CPU_ADDR_MIRROR; u16 pat_index = (*bind_ops)[i].pat_index; u16 coh_mode; + bool comp_en; if (XE_IOCTL_DBG(xe, is_cpu_addr_mirror && (!xe_vm_in_fault_mode(vm) || @@ -3421,6 +3422,7 @@ static int vm_bind_ioctl_check_args(struct xe_device *xe, struct xe_vm *vm, pat_index = array_index_nospec(pat_index, xe->pat.n_entries); (*bind_ops)[i].pat_index = pat_index; coh_mode = xe_pat_index_get_coh_mode(xe, pat_index); + comp_en = xe_pat_index_get_comp_en(xe, pat_index); if (XE_IOCTL_DBG(xe, !coh_mode)) { /* hw reserved */ err = -EINVAL; goto free_bind_ops; @@ -3451,6 +3453,8 @@ static int vm_bind_ioctl_check_args(struct xe_device *xe, struct xe_vm *vm, op == DRM_XE_VM_BIND_OP_MAP_USERPTR) || XE_IOCTL_DBG(xe, coh_mode == XE_COH_NONE && op == DRM_XE_VM_BIND_OP_MAP_USERPTR) || + XE_IOCTL_DBG(xe, comp_en && + op == DRM_XE_VM_BIND_OP_MAP_USERPTR) || XE_IOCTL_DBG(xe, op == DRM_XE_VM_BIND_OP_MAP_USERPTR && !IS_ENABLED(CONFIG_DRM_GPUSVM)) || XE_IOCTL_DBG(xe, obj && @@ -3529,6 +3533,7 @@ static int xe_vm_bind_ioctl_validate_bo(struct xe_device *xe, struct xe_bo *bo, u16 pat_index, u32 op, u32 bind_flags) { u16 coh_mode; + bool comp_en; if (XE_IOCTL_DBG(xe, (bo->flags & XE_BO_FLAG_NO_COMPRESSION) && xe_pat_index_get_comp_en(xe, pat_index))) @@ -3574,6 +3579,14 @@ static int xe_vm_bind_ioctl_validate_bo(struct xe_device *xe, struct xe_bo *bo, return -EINVAL; } + /* + * Ensures that imported buffer objects (dma-bufs) are not mapped + * with a PAT index that enables compression. + */ + comp_en = xe_pat_index_get_comp_en(xe, pat_index); + if (XE_IOCTL_DBG(xe, bo->ttm.base.import_attach && comp_en)) + return -EINVAL; + /* If a BO is protected it can only be mapped if the key is still valid */ if ((bind_flags & DRM_XE_VM_BIND_FLAG_CHECK_PXP) && xe_bo_is_protected(bo) && op != DRM_XE_VM_BIND_OP_UNMAP && op != DRM_XE_VM_BIND_OP_UNMAP_ALL) -- cgit v1.2.3 From e70f43c21dbfa305a304028577a8565379089768 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Fri, 9 Jan 2026 17:27:33 -0800 Subject: drm/xe: Add dedicated message lock Stop abusing DRM scheduler job list lock for messages, add dedicated message lock. Signed-off-by: Matthew Brost Reviewed-by: Niranjana Vishwanathapura Acked-by: Philipp Stanner Link: https://patch.msgid.link/20260110012739.2888434-2-matthew.brost@intel.com --- drivers/gpu/drm/xe/xe_gpu_scheduler.c | 5 +++-- drivers/gpu/drm/xe/xe_gpu_scheduler.h | 4 ++-- drivers/gpu/drm/xe/xe_gpu_scheduler_types.h | 2 ++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_gpu_scheduler.c b/drivers/gpu/drm/xe/xe_gpu_scheduler.c index f91e06d03511..f4f23317191f 100644 --- a/drivers/gpu/drm/xe/xe_gpu_scheduler.c +++ b/drivers/gpu/drm/xe/xe_gpu_scheduler.c @@ -77,6 +77,7 @@ int xe_sched_init(struct xe_gpu_scheduler *sched, }; sched->ops = xe_ops; + spin_lock_init(&sched->msg_lock); INIT_LIST_HEAD(&sched->msgs); INIT_WORK(&sched->work_process_msg, xe_sched_process_msg_work); @@ -117,7 +118,7 @@ void xe_sched_add_msg(struct xe_gpu_scheduler *sched, void xe_sched_add_msg_locked(struct xe_gpu_scheduler *sched, struct xe_sched_msg *msg) { - lockdep_assert_held(&sched->base.job_list_lock); + lockdep_assert_held(&sched->msg_lock); list_add_tail(&msg->link, &sched->msgs); xe_sched_process_msg_queue(sched); @@ -131,7 +132,7 @@ void xe_sched_add_msg_locked(struct xe_gpu_scheduler *sched, void xe_sched_add_msg_head(struct xe_gpu_scheduler *sched, struct xe_sched_msg *msg) { - lockdep_assert_held(&sched->base.job_list_lock); + lockdep_assert_held(&sched->msg_lock); list_add(&msg->link, &sched->msgs); xe_sched_process_msg_queue(sched); diff --git a/drivers/gpu/drm/xe/xe_gpu_scheduler.h b/drivers/gpu/drm/xe/xe_gpu_scheduler.h index c7a77a3a9681..dceb2cd0ee5b 100644 --- a/drivers/gpu/drm/xe/xe_gpu_scheduler.h +++ b/drivers/gpu/drm/xe/xe_gpu_scheduler.h @@ -33,12 +33,12 @@ void xe_sched_add_msg_head(struct xe_gpu_scheduler *sched, static inline void xe_sched_msg_lock(struct xe_gpu_scheduler *sched) { - spin_lock(&sched->base.job_list_lock); + spin_lock(&sched->msg_lock); } static inline void xe_sched_msg_unlock(struct xe_gpu_scheduler *sched) { - spin_unlock(&sched->base.job_list_lock); + spin_unlock(&sched->msg_lock); } static inline void xe_sched_stop(struct xe_gpu_scheduler *sched) diff --git a/drivers/gpu/drm/xe/xe_gpu_scheduler_types.h b/drivers/gpu/drm/xe/xe_gpu_scheduler_types.h index 6731b13da8bb..63d9bf92583c 100644 --- a/drivers/gpu/drm/xe/xe_gpu_scheduler_types.h +++ b/drivers/gpu/drm/xe/xe_gpu_scheduler_types.h @@ -47,6 +47,8 @@ struct xe_gpu_scheduler { const struct xe_sched_backend_ops *ops; /** @msgs: list of messages to be processed in @work_process_msg */ struct list_head msgs; + /** @msg_lock: Message lock */ + spinlock_t msg_lock; /** @work_process_msg: processes messages */ struct work_struct work_process_msg; }; -- cgit v1.2.3 From 95f27831ee3c6afc2e3b7386c32545eba1f096d7 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Fri, 9 Jan 2026 17:27:34 -0800 Subject: drm/xe: Stop abusing DRM scheduler internals Use new pending job list iterator and new helper functions in Xe to avoid reaching into DRM scheduler internals. Part of this change involves removing pending jobs debug information from debugfs and devcoredump. As agreed, the pending job list should only be accessed when the scheduler is stopped. However, it's not straightforward to determine whether the scheduler is stopped from the shared debugfs/devcoredump code path. Additionally, the pending job list provides little useful information, as pending jobs can be inferred from seqnos and ring head/tail positions. Therefore, this debug information is being removed. v4: - Add comment around DRM_GPU_SCHED_STAT_NO_HANG (Niranjana) Signed-off-by: Matthew Brost Reviewed-by: Niranjana Vishwanathapura Link: https://patch.msgid.link/20260110012739.2888434-3-matthew.brost@intel.com --- drivers/gpu/drm/xe/xe_gpu_scheduler.c | 4 +- drivers/gpu/drm/xe/xe_gpu_scheduler.h | 33 +++---------- drivers/gpu/drm/xe/xe_guc_submit.c | 81 +++++++------------------------- drivers/gpu/drm/xe/xe_guc_submit_types.h | 11 ----- drivers/gpu/drm/xe/xe_hw_fence.c | 16 ------- drivers/gpu/drm/xe/xe_hw_fence.h | 2 - 6 files changed, 27 insertions(+), 120 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_gpu_scheduler.c b/drivers/gpu/drm/xe/xe_gpu_scheduler.c index f4f23317191f..9c8004d5dd91 100644 --- a/drivers/gpu/drm/xe/xe_gpu_scheduler.c +++ b/drivers/gpu/drm/xe/xe_gpu_scheduler.c @@ -7,7 +7,7 @@ static void xe_sched_process_msg_queue(struct xe_gpu_scheduler *sched) { - if (!READ_ONCE(sched->base.pause_submit)) + if (!drm_sched_is_stopped(&sched->base)) queue_work(sched->base.submit_wq, &sched->work_process_msg); } @@ -43,7 +43,7 @@ static void xe_sched_process_msg_work(struct work_struct *w) container_of(w, struct xe_gpu_scheduler, work_process_msg); struct xe_sched_msg *msg; - if (READ_ONCE(sched->base.pause_submit)) + if (drm_sched_is_stopped(&sched->base)) return; msg = xe_sched_get_msg(sched); diff --git a/drivers/gpu/drm/xe/xe_gpu_scheduler.h b/drivers/gpu/drm/xe/xe_gpu_scheduler.h index dceb2cd0ee5b..664c2db56af3 100644 --- a/drivers/gpu/drm/xe/xe_gpu_scheduler.h +++ b/drivers/gpu/drm/xe/xe_gpu_scheduler.h @@ -56,12 +56,9 @@ static inline void xe_sched_resubmit_jobs(struct xe_gpu_scheduler *sched) struct drm_sched_job *s_job; bool restore_replay = false; - list_for_each_entry(s_job, &sched->base.pending_list, list) { - struct drm_sched_fence *s_fence = s_job->s_fence; - struct dma_fence *hw_fence = s_fence->parent; - + drm_sched_for_each_pending_job(s_job, &sched->base, NULL) { restore_replay |= to_xe_sched_job(s_job)->restore_replay; - if (restore_replay || (hw_fence && !dma_fence_is_signaled(hw_fence))) + if (restore_replay || !drm_sched_job_is_signaled(s_job)) sched->base.ops->run_job(s_job); } } @@ -72,14 +69,6 @@ xe_sched_invalidate_job(struct xe_sched_job *job, int threshold) return drm_sched_invalidate_job(&job->drm, threshold); } -static inline void xe_sched_add_pending_job(struct xe_gpu_scheduler *sched, - struct xe_sched_job *job) -{ - spin_lock(&sched->base.job_list_lock); - list_add(&job->drm.list, &sched->base.pending_list); - spin_unlock(&sched->base.job_list_lock); -} - /** * xe_sched_first_pending_job() - Find first pending job which is unsignaled * @sched: Xe GPU scheduler @@ -89,21 +78,13 @@ static inline void xe_sched_add_pending_job(struct xe_gpu_scheduler *sched, static inline struct xe_sched_job *xe_sched_first_pending_job(struct xe_gpu_scheduler *sched) { - struct xe_sched_job *job, *r_job = NULL; - - spin_lock(&sched->base.job_list_lock); - list_for_each_entry(job, &sched->base.pending_list, drm.list) { - struct drm_sched_fence *s_fence = job->drm.s_fence; - struct dma_fence *hw_fence = s_fence->parent; + struct drm_sched_job *job; - if (hw_fence && !dma_fence_is_signaled(hw_fence)) { - r_job = job; - break; - } - } - spin_unlock(&sched->base.job_list_lock); + drm_sched_for_each_pending_job(job, &sched->base, NULL) + if (!drm_sched_job_is_signaled(job)) + return to_xe_sched_job(job); - return r_job; + return NULL; } static inline int diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index 45aa56b30a12..b7824834ff33 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -1374,7 +1374,7 @@ static void xe_guc_exec_queue_lr_cleanup(struct work_struct *w) struct xe_exec_queue *q = ge->q; struct xe_guc *guc = exec_queue_to_guc(q); struct xe_gpu_scheduler *sched = &ge->sched; - struct xe_sched_job *job; + struct drm_sched_job *job; bool wedged = false; xe_gt_assert(guc_to_gt(guc), xe_exec_queue_is_lr(q)); @@ -1433,16 +1433,10 @@ static void xe_guc_exec_queue_lr_cleanup(struct work_struct *w) if (!exec_queue_killed(q) && !xe_lrc_ring_is_idle(q->lrc[0])) xe_devcoredump(q, NULL, "LR job cleanup, guc_id=%d", q->guc->id); - xe_hw_fence_irq_stop(q->fence_irq); + drm_sched_for_each_pending_job(job, &sched->base, NULL) + xe_sched_job_set_error(to_xe_sched_job(job), -ECANCELED); xe_sched_submission_start(sched); - - spin_lock(&sched->base.job_list_lock); - list_for_each_entry(job, &sched->base.pending_list, drm.list) - xe_sched_job_set_error(job, -ECANCELED); - spin_unlock(&sched->base.job_list_lock); - - xe_hw_fence_irq_start(q->fence_irq); } #define ADJUST_FIVE_PERCENT(__t) mul_u64_u32_div(__t, 105, 100) @@ -1570,7 +1564,7 @@ static enum drm_gpu_sched_stat guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) { struct xe_sched_job *job = to_xe_sched_job(drm_job); - struct xe_sched_job *tmp_job; + struct drm_sched_job *tmp_job; struct xe_exec_queue *q = job->q; struct xe_gpu_scheduler *sched = &q->guc->sched; struct xe_guc *guc = exec_queue_to_guc(q); @@ -1578,7 +1572,6 @@ 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; - int i = 0; bool wedged = false, skip_timeout_check; xe_gt_assert(guc_to_gt(guc), !xe_exec_queue_is_lr(q)); @@ -1756,14 +1749,11 @@ trigger_reset: __deregister_exec_queue(guc, q); } - /* Stop fence signaling */ - xe_hw_fence_irq_stop(q->fence_irq); + /* Mark all outstanding jobs as bad, thus completing them */ + 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); - /* - * Fence state now stable, stop / start scheduler which cleans up any - * fences that are complete - */ - xe_sched_add_pending_job(sched, job); xe_sched_submission_start(sched); if (xe_exec_queue_is_multi_queue(q)) @@ -1771,16 +1761,11 @@ trigger_reset: else xe_guc_exec_queue_trigger_cleanup(q); - /* Mark all outstanding jobs as bad, thus completing them */ - spin_lock(&sched->base.job_list_lock); - list_for_each_entry(tmp_job, &sched->base.pending_list, drm.list) - xe_sched_job_set_error(tmp_job, !i++ ? err : -ECANCELED); - spin_unlock(&sched->base.job_list_lock); - - /* Start fence signaling */ - xe_hw_fence_irq_start(q->fence_irq); - - return DRM_GPU_SCHED_STAT_RESET; + /* + * We want the job added back to the pending list so it gets freed; this + * is what DRM_GPU_SCHED_STAT_NO_HANG does. + */ + return DRM_GPU_SCHED_STAT_NO_HANG; sched_enable: set_exec_queue_pending_tdr_exit(q); @@ -2754,11 +2739,12 @@ static void guc_exec_queue_unpause_prepare(struct xe_guc *guc, struct xe_exec_queue *q) { struct xe_gpu_scheduler *sched = &q->guc->sched; - struct xe_sched_job *job = NULL, *__job; + struct xe_sched_job *job = NULL; + struct drm_sched_job *s_job; bool restore_replay = false; - list_for_each_entry(__job, &sched->base.pending_list, drm.list) { - job = __job; + drm_sched_for_each_pending_job(s_job, &sched->base, NULL) { + job = to_xe_sched_job(s_job); restore_replay |= job->restore_replay; if (restore_replay) { xe_gt_dbg(guc_to_gt(guc), "Replay JOB - guc_id=%d, seqno=%d", @@ -2882,7 +2868,7 @@ void xe_guc_submit_unpause_vf(struct xe_guc *guc) * created after resfix done. */ if (q->guc->id != index || - !READ_ONCE(q->guc->sched.base.pause_submit)) + !drm_sched_is_stopped(&q->guc->sched.base)) continue; guc_exec_queue_unpause(guc, q); @@ -3387,29 +3373,6 @@ xe_guc_exec_queue_snapshot_capture(struct xe_exec_queue *q) snapshot->multi_queue.primary = xe_exec_queue_multi_queue_primary(q)->guc->id; snapshot->multi_queue.pos = q->multi_queue.pos; } - spin_lock(&sched->base.job_list_lock); - snapshot->pending_list_size = list_count_nodes(&sched->base.pending_list); - snapshot->pending_list = kmalloc_array(snapshot->pending_list_size, - sizeof(struct pending_list_snapshot), - GFP_ATOMIC); - - if (snapshot->pending_list) { - struct xe_sched_job *job_iter; - - i = 0; - list_for_each_entry(job_iter, &sched->base.pending_list, drm.list) { - snapshot->pending_list[i].seqno = - xe_sched_job_seqno(job_iter); - snapshot->pending_list[i].fence = - dma_fence_is_signaled(job_iter->fence) ? 1 : 0; - snapshot->pending_list[i].finished = - dma_fence_is_signaled(&job_iter->drm.s_fence->finished) - ? 1 : 0; - i++; - } - } - - spin_unlock(&sched->base.job_list_lock); return snapshot; } @@ -3473,13 +3436,6 @@ xe_guc_exec_queue_snapshot_print(struct xe_guc_submit_exec_queue_snapshot *snaps drm_printf(p, "\tMulti queue primary GuC ID: %d\n", snapshot->multi_queue.primary); drm_printf(p, "\tMulti queue position: %d\n", snapshot->multi_queue.pos); } - - for (i = 0; snapshot->pending_list && i < snapshot->pending_list_size; - i++) - drm_printf(p, "\tJob: seqno=%d, fence=%d, finished=%d\n", - snapshot->pending_list[i].seqno, - snapshot->pending_list[i].fence, - snapshot->pending_list[i].finished); } /** @@ -3502,7 +3458,6 @@ void xe_guc_exec_queue_snapshot_free(struct xe_guc_submit_exec_queue_snapshot *s xe_lrc_snapshot_free(snapshot->lrc[i]); kfree(snapshot->lrc); } - kfree(snapshot->pending_list); kfree(snapshot); } diff --git a/drivers/gpu/drm/xe/xe_guc_submit_types.h b/drivers/gpu/drm/xe/xe_guc_submit_types.h index 25e29e85502c..5ccc5f959bb3 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit_types.h +++ b/drivers/gpu/drm/xe/xe_guc_submit_types.h @@ -61,12 +61,6 @@ struct guc_submit_parallel_scratch { u32 wq[WQ_SIZE / sizeof(u32)]; }; -struct pending_list_snapshot { - u32 seqno; - bool fence; - bool finished; -}; - /** * struct xe_guc_submit_exec_queue_snapshot - Snapshot for devcoredump */ @@ -147,11 +141,6 @@ struct xe_guc_submit_exec_queue_snapshot { /** @valid: The exec queue is part of a multi queue group */ bool valid; } multi_queue; - - /** @pending_list_size: Size of the pending list snapshot array */ - int pending_list_size; - /** @pending_list: snapshot of the pending list info */ - struct pending_list_snapshot *pending_list; }; #endif diff --git a/drivers/gpu/drm/xe/xe_hw_fence.c b/drivers/gpu/drm/xe/xe_hw_fence.c index f6057456e460..6b5bc67767d3 100644 --- a/drivers/gpu/drm/xe/xe_hw_fence.c +++ b/drivers/gpu/drm/xe/xe_hw_fence.c @@ -108,22 +108,6 @@ void xe_hw_fence_irq_run(struct xe_hw_fence_irq *irq) irq_work_queue(&irq->work); } -void xe_hw_fence_irq_stop(struct xe_hw_fence_irq *irq) -{ - spin_lock_irq(&irq->lock); - irq->enabled = false; - spin_unlock_irq(&irq->lock); -} - -void xe_hw_fence_irq_start(struct xe_hw_fence_irq *irq) -{ - spin_lock_irq(&irq->lock); - irq->enabled = true; - spin_unlock_irq(&irq->lock); - - irq_work_queue(&irq->work); -} - void xe_hw_fence_ctx_init(struct xe_hw_fence_ctx *ctx, struct xe_gt *gt, struct xe_hw_fence_irq *irq, const char *name) { diff --git a/drivers/gpu/drm/xe/xe_hw_fence.h b/drivers/gpu/drm/xe/xe_hw_fence.h index f13a1c4982c7..599492c13f80 100644 --- a/drivers/gpu/drm/xe/xe_hw_fence.h +++ b/drivers/gpu/drm/xe/xe_hw_fence.h @@ -17,8 +17,6 @@ void xe_hw_fence_module_exit(void); void xe_hw_fence_irq_init(struct xe_hw_fence_irq *irq); void xe_hw_fence_irq_finish(struct xe_hw_fence_irq *irq); void xe_hw_fence_irq_run(struct xe_hw_fence_irq *irq); -void xe_hw_fence_irq_stop(struct xe_hw_fence_irq *irq); -void xe_hw_fence_irq_start(struct xe_hw_fence_irq *irq); void xe_hw_fence_ctx_init(struct xe_hw_fence_ctx *ctx, struct xe_gt *gt, struct xe_hw_fence_irq *irq, const char *name); -- cgit v1.2.3 From dd1ef5e2456558876244795bb22a4d90cb24f160 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Fri, 9 Jan 2026 17:27:35 -0800 Subject: drm/xe: Only toggle scheduling in TDR if GuC is running If the firmware is not running during TDR (e.g., when the driver is unloading), there's no need to toggle scheduling in the GuC. In such cases, skip this step. v4: - Bail on wait UC not running (Niranjana) Signed-off-by: Matthew Brost Reviewed-by: Niranjana Vishwanathapura Link: https://patch.msgid.link/20260110012739.2888434-4-matthew.brost@intel.com --- drivers/gpu/drm/xe/xe_guc_submit.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index b7824834ff33..7b0bbe48d2aa 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -1638,7 +1638,7 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) if (exec_queue_reset(q)) err = -EIO; - if (!exec_queue_destroyed(q)) { + if (!exec_queue_destroyed(q) && xe_uc_fw_is_running(&guc->fw)) { /* * Wait for any pending G2H to flush out before * modifying state @@ -1673,6 +1673,7 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) */ smp_rmb(); ret = wait_event_timeout(guc->ct.wq, + !xe_uc_fw_is_running(&guc->fw) || !exec_queue_pending_disable(q) || xe_guc_read_stopped(guc) || vf_recovery(guc), HZ * 5); -- cgit v1.2.3 From 58624c195b9a90950ebff166b72ee712f8d5a4c7 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Fri, 9 Jan 2026 17:27:36 -0800 Subject: drm/xe: Do not deregister queues in TDR Deregistering queues in the TDR introduces unnecessary complexity, requiring reference-counting techniques to function correctly, particularly to prevent use-after-free (UAF) issues while a deregistration initiated from the TDR is in progress. All that's needed in the TDR is to kick the queue off the hardware, which is achieved by disabling scheduling. Queue deregistration should be handled in a single, well-defined point in the cleanup path, tied to the queue's reference count. v4: - Explain why extra ref were needed prior to this patch (Niranjana) Signed-off-by: Matthew Brost Reviewed-by: Niranjana Vishwanathapura Link: https://patch.msgid.link/20260110012739.2888434-5-matthew.brost@intel.com --- drivers/gpu/drm/xe/xe_guc_submit.c | 70 ++++++-------------------------------- 1 file changed, 10 insertions(+), 60 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index 7b0bbe48d2aa..64ea246a1fb8 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -72,10 +72,9 @@ 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_CHECK_TIMEOUT (1 << 10) -#define EXEC_QUEUE_STATE_EXTRA_REF (1 << 11) -#define EXEC_QUEUE_STATE_PENDING_RESUME (1 << 12) -#define EXEC_QUEUE_STATE_PENDING_TDR_EXIT (1 << 13) -#define EXEC_QUEUE_STATE_IDLE_SKIP_SUSPEND (1 << 14) +#define EXEC_QUEUE_STATE_PENDING_RESUME (1 << 11) +#define EXEC_QUEUE_STATE_PENDING_TDR_EXIT (1 << 12) +#define EXEC_QUEUE_STATE_IDLE_SKIP_SUSPEND (1 << 13) static bool exec_queue_registered(struct xe_exec_queue *q) { @@ -222,21 +221,6 @@ static void clear_exec_queue_check_timeout(struct xe_exec_queue *q) atomic_and(~EXEC_QUEUE_STATE_CHECK_TIMEOUT, &q->guc->state); } -static bool exec_queue_extra_ref(struct xe_exec_queue *q) -{ - return atomic_read(&q->guc->state) & EXEC_QUEUE_STATE_EXTRA_REF; -} - -static void set_exec_queue_extra_ref(struct xe_exec_queue *q) -{ - atomic_or(EXEC_QUEUE_STATE_EXTRA_REF, &q->guc->state); -} - -static void clear_exec_queue_extra_ref(struct xe_exec_queue *q) -{ - atomic_and(~EXEC_QUEUE_STATE_EXTRA_REF, &q->guc->state); -} - static bool exec_queue_pending_resume(struct xe_exec_queue *q) { return atomic_read(&q->guc->state) & EXEC_QUEUE_STATE_PENDING_RESUME; @@ -1538,28 +1522,6 @@ static void disable_scheduling(struct xe_exec_queue *q, bool immediate) G2H_LEN_DW_SCHED_CONTEXT_MODE_SET, 1); } -static void __deregister_exec_queue(struct xe_guc *guc, struct xe_exec_queue *q) -{ - u32 action[] = { - XE_GUC_ACTION_DEREGISTER_CONTEXT, - q->guc->id, - }; - - 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_enable(q)); - xe_gt_assert(guc_to_gt(guc), !exec_queue_pending_disable(q)); - - set_exec_queue_destroyed(q); - trace_xe_exec_queue_deregister(q); - - if (xe_exec_queue_is_multi_queue_secondary(q)) - handle_deregister_done(guc, q); - else - xe_guc_ct_send(&guc->ct, action, ARRAY_SIZE(action), - G2H_LEN_DW_DEREGISTER_CONTEXT, 1); -} - static enum drm_gpu_sched_stat guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) { @@ -1575,6 +1537,7 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) bool wedged = false, skip_timeout_check; xe_gt_assert(guc_to_gt(guc), !xe_exec_queue_is_lr(q)); + xe_gt_assert(guc_to_gt(guc), !exec_queue_destroyed(q)); /* * TDR has fired before free job worker. Common if exec queue @@ -1591,8 +1554,7 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) /* Must check all state after stopping scheduler */ skip_timeout_check = exec_queue_reset(q) || - exec_queue_killed_or_banned_or_wedged(q) || - exec_queue_destroyed(q); + exec_queue_killed_or_banned_or_wedged(q); /* Skip timeout check if multi-queue group is banned */ if (xe_exec_queue_is_multi_queue(q) && @@ -1632,13 +1594,13 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) wedged = guc_submit_hint_wedged(exec_queue_to_guc(q)); /* Engine state now stable, disable scheduling to check timestamp */ - if (!wedged && exec_queue_registered(q)) { + if (!wedged && (exec_queue_enabled(q) || exec_queue_pending_disable(q))) { int ret; if (exec_queue_reset(q)) err = -EIO; - if (!exec_queue_destroyed(q) && xe_uc_fw_is_running(&guc->fw)) { + if (xe_uc_fw_is_running(&guc->fw)) { /* * Wait for any pending G2H to flush out before * modifying state @@ -1688,8 +1650,6 @@ trigger_reset: xe_devcoredump(q, job, "Schedule disable failed to respond, guc_id=%d, ret=%d, guc_read=%d", q->guc->id, ret, xe_guc_read_stopped(guc)); - set_exec_queue_extra_ref(q); - xe_exec_queue_get(q); /* GT reset owns this */ set_exec_queue_banned(q); xe_gt_reset_async(q->gt); xe_sched_tdr_queue_imm(sched); @@ -1742,13 +1702,7 @@ trigger_reset: } } - /* Finish cleaning up exec queue via deregister */ set_exec_queue_banned(q); - if (!wedged && exec_queue_registered(q) && !exec_queue_destroyed(q)) { - set_exec_queue_extra_ref(q); - xe_exec_queue_get(q); - __deregister_exec_queue(guc, q); - } /* Mark all outstanding jobs as bad, thus completing them */ xe_sched_job_set_error(job, err); @@ -2419,7 +2373,7 @@ static void guc_exec_queue_stop(struct xe_guc *guc, struct xe_exec_queue *q) /* Clean up lost G2H + reset engine state */ if (exec_queue_registered(q)) { - if (exec_queue_extra_ref(q) || xe_exec_queue_is_lr(q)) + if (xe_exec_queue_is_lr(q)) xe_exec_queue_put(q); else if (exec_queue_destroyed(q)) __guc_exec_queue_destroy(guc, q); @@ -2553,11 +2507,7 @@ static void guc_exec_queue_revert_pending_state_change(struct xe_guc *guc, if (exec_queue_destroyed(q) && exec_queue_registered(q)) { clear_exec_queue_destroyed(q); - if (exec_queue_extra_ref(q)) - xe_exec_queue_put(q); - else - q->guc->needs_cleanup = true; - clear_exec_queue_extra_ref(q); + q->guc->needs_cleanup = true; xe_gt_dbg(guc_to_gt(guc), "Replay CLEANUP - guc_id=%d", q->guc->id); } @@ -3037,7 +2987,7 @@ static void handle_deregister_done(struct xe_guc *guc, struct xe_exec_queue *q) clear_exec_queue_registered(q); - if (exec_queue_extra_ref(q) || xe_exec_queue_is_lr(q)) + if (xe_exec_queue_is_lr(q)) xe_exec_queue_put(q); else __guc_exec_queue_destroy(guc, q); -- cgit v1.2.3 From ddb5cf9b90c5201a833d5d65f96b359bf3acdd90 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Fri, 9 Jan 2026 17:27:37 -0800 Subject: drm/xe: Remove special casing for LR queues in submission Now that LR jobs are tracked by the DRM scheduler, there's no longer a need to special-case LR queues. This change removes all LR queue-specific handling, including dedicated TDR logic, reference counting schemes, and other related mechanisms. v4: - Remove xe_exec_queue_lr_cleanup tracepoint (Niranjana) Signed-off-by: Matthew Brost Reviewed-by: Niranjana Vishwanathapura Link: https://patch.msgid.link/20260110012739.2888434-6-matthew.brost@intel.com --- drivers/gpu/drm/xe/xe_guc_exec_queue_types.h | 2 - drivers/gpu/drm/xe/xe_guc_submit.c | 131 +++------------------------ drivers/gpu/drm/xe/xe_trace.h | 5 - 3 files changed, 11 insertions(+), 127 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_guc_exec_queue_types.h b/drivers/gpu/drm/xe/xe_guc_exec_queue_types.h index a3b034e4b205..fd0915ed8eb1 100644 --- a/drivers/gpu/drm/xe/xe_guc_exec_queue_types.h +++ b/drivers/gpu/drm/xe/xe_guc_exec_queue_types.h @@ -33,8 +33,6 @@ struct xe_guc_exec_queue { */ #define MAX_STATIC_MSG_TYPE 3 struct xe_sched_msg static_msgs[MAX_STATIC_MSG_TYPE]; - /** @lr_tdr: long running TDR worker */ - struct work_struct lr_tdr; /** @destroy_async: do final destroy async from this worker */ struct work_struct destroy_async; /** @resume_time: time of last resume */ diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index 64ea246a1fb8..1ddf465698ee 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -587,10 +587,7 @@ static void xe_guc_exec_queue_trigger_cleanup(struct xe_exec_queue *q) /** to wakeup xe_wait_user_fence ioctl if exec queue is reset */ wake_up_all(&xe->ufence_wq); - if (xe_exec_queue_is_lr(q)) - queue_work(guc_to_gt(guc)->ordered_wq, &q->guc->lr_tdr); - else - xe_sched_tdr_queue_imm(&q->guc->sched); + xe_sched_tdr_queue_imm(&q->guc->sched); } static void xe_guc_exec_queue_group_trigger_cleanup(struct xe_exec_queue *q) @@ -978,14 +975,6 @@ static void register_exec_queue(struct xe_exec_queue *q, int ctx_type) parallel_write(xe, map, wq_desc.wq_status, WQ_STATUS_ACTIVE); } - /* - * We must keep a reference for LR engines if engine is registered with - * the GuC as jobs signal immediately and can't destroy an engine if the - * GuC has a reference to it. - */ - if (xe_exec_queue_is_lr(q)) - xe_exec_queue_get(q); - set_exec_queue_registered(q); trace_xe_exec_queue_register(q); if (xe_exec_queue_is_multi_queue_primary(q)) @@ -1186,7 +1175,7 @@ guc_exec_queue_run_job(struct drm_sched_job *drm_job) struct xe_sched_job *job = to_xe_sched_job(drm_job); struct xe_exec_queue *q = job->q; struct xe_guc *guc = exec_queue_to_guc(q); - bool lr = xe_exec_queue_is_lr(q), killed_or_banned_or_wedged = + bool killed_or_banned_or_wedged = exec_queue_killed_or_banned_or_wedged(q); xe_gt_assert(guc_to_gt(guc), !(exec_queue_destroyed(q) || exec_queue_pending_disable(q)) || @@ -1216,14 +1205,6 @@ guc_exec_queue_run_job(struct drm_sched_job *drm_job) } run_job_out: - /* - * We don't care about job-fence ordering in LR VMs because these fences - * are never exported; they are used solely to keep jobs on the pending - * list. Once a queue enters an error state, there's no need to track - * them. - */ - if (killed_or_banned_or_wedged && lr) - xe_sched_job_set_error(job, -ECANCELED); return job->fence; } @@ -1275,8 +1256,7 @@ static void disable_scheduling_deregister(struct xe_guc *guc, xe_gt_warn(q->gt, "Pending enable/disable failed to respond\n"); xe_sched_submission_start(sched); xe_gt_reset_async(q->gt); - if (!xe_exec_queue_is_lr(q)) - xe_sched_tdr_queue_imm(sched); + xe_sched_tdr_queue_imm(sched); return; } @@ -1351,78 +1331,6 @@ static bool guc_submit_hint_wedged(struct xe_guc *guc) return true; } -static void xe_guc_exec_queue_lr_cleanup(struct work_struct *w) -{ - struct xe_guc_exec_queue *ge = - container_of(w, struct xe_guc_exec_queue, lr_tdr); - struct xe_exec_queue *q = ge->q; - struct xe_guc *guc = exec_queue_to_guc(q); - struct xe_gpu_scheduler *sched = &ge->sched; - struct drm_sched_job *job; - bool wedged = false; - - xe_gt_assert(guc_to_gt(guc), xe_exec_queue_is_lr(q)); - - if (vf_recovery(guc)) - return; - - trace_xe_exec_queue_lr_cleanup(q); - - if (!exec_queue_killed(q)) - wedged = guc_submit_hint_wedged(exec_queue_to_guc(q)); - - /* Kill the run_job / process_msg entry points */ - xe_sched_submission_stop(sched); - - /* - * Engine state now mostly stable, disable scheduling / deregister if - * needed. This cleanup routine might be called multiple times, where - * the actual async engine deregister drops the final engine ref. - * Calling disable_scheduling_deregister will mark the engine as - * destroyed and fire off the CT requests to disable scheduling / - * deregister, which we only want to do once. We also don't want to mark - * the engine as pending_disable again as this may race with the - * xe_guc_deregister_done_handler() which treats it as an unexpected - * state. - */ - if (!wedged && exec_queue_registered(q) && !exec_queue_destroyed(q)) { - struct xe_guc *guc = exec_queue_to_guc(q); - int ret; - - set_exec_queue_banned(q); - disable_scheduling_deregister(guc, q); - - /* - * Must wait for scheduling to be disabled before signalling - * any fences, if GT broken the GT reset code should signal us. - */ - ret = wait_event_timeout(guc->ct.wq, - !exec_queue_pending_disable(q) || - xe_guc_read_stopped(guc) || - vf_recovery(guc), HZ * 5); - if (vf_recovery(guc)) - return; - - if (!ret) { - xe_gt_warn(q->gt, "Schedule disable failed to respond, guc_id=%d\n", - q->guc->id); - xe_devcoredump(q, NULL, "Schedule disable failed to respond, guc_id=%d\n", - q->guc->id); - xe_sched_submission_start(sched); - xe_gt_reset_async(q->gt); - return; - } - } - - if (!exec_queue_killed(q) && !xe_lrc_ring_is_idle(q->lrc[0])) - xe_devcoredump(q, NULL, "LR job cleanup, guc_id=%d", q->guc->id); - - drm_sched_for_each_pending_job(job, &sched->base, NULL) - xe_sched_job_set_error(to_xe_sched_job(job), -ECANCELED); - - xe_sched_submission_start(sched); -} - #define ADJUST_FIVE_PERCENT(__t) mul_u64_u32_div(__t, 105, 100) static bool check_timeout(struct xe_exec_queue *q, struct xe_sched_job *job) @@ -1495,8 +1403,7 @@ static void enable_scheduling(struct xe_exec_queue *q) xe_gt_warn(guc_to_gt(guc), "Schedule enable failed to respond"); set_exec_queue_banned(q); xe_gt_reset_async(q->gt); - if (!xe_exec_queue_is_lr(q)) - xe_sched_tdr_queue_imm(&q->guc->sched); + xe_sched_tdr_queue_imm(&q->guc->sched); } } @@ -1536,7 +1443,6 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) pid_t pid = -1; bool wedged = false, skip_timeout_check; - xe_gt_assert(guc_to_gt(guc), !xe_exec_queue_is_lr(q)); xe_gt_assert(guc_to_gt(guc), !exec_queue_destroyed(q)); /* @@ -1561,6 +1467,10 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) READ_ONCE(q->multi_queue.group->banned)) skip_timeout_check = true; + /* LR jobs can only get here if queue has been killed or hit an error */ + if (xe_exec_queue_is_lr(q)) + xe_gt_assert(guc_to_gt(guc), skip_timeout_check); + /* * FIXME: In multi-queue scenario, the TDR must ensure that the whole * multi-queue group is off the HW before signaling the fences to avoid @@ -1770,8 +1680,6 @@ static void __guc_exec_queue_destroy_async(struct work_struct *w) mutex_unlock(&group->list_lock); } - if (xe_exec_queue_is_lr(q)) - cancel_work_sync(&ge->lr_tdr); /* Confirm no work left behind accessing device structures */ cancel_delayed_work_sync(&ge->sched.base.work_tdr); @@ -2075,9 +1983,6 @@ static int guc_exec_queue_init(struct xe_exec_queue *q) if (err) goto err_sched; - if (xe_exec_queue_is_lr(q)) - INIT_WORK(&q->guc->lr_tdr, xe_guc_exec_queue_lr_cleanup); - mutex_lock(&guc->submission_state.lock); err = alloc_guc_id(guc, q); @@ -2373,9 +2278,7 @@ static void guc_exec_queue_stop(struct xe_guc *guc, struct xe_exec_queue *q) /* Clean up lost G2H + reset engine state */ if (exec_queue_registered(q)) { - if (xe_exec_queue_is_lr(q)) - xe_exec_queue_put(q); - else if (exec_queue_destroyed(q)) + if (exec_queue_destroyed(q)) __guc_exec_queue_destroy(guc, q); } if (q->guc->suspend_pending) { @@ -2405,9 +2308,6 @@ static void guc_exec_queue_stop(struct xe_guc *guc, struct xe_exec_queue *q) trace_xe_sched_job_ban(job); ban = true; } - } else if (xe_exec_queue_is_lr(q) && - !xe_lrc_ring_is_idle(q->lrc[0])) { - ban = true; } if (ban) { @@ -2490,8 +2390,6 @@ static void guc_exec_queue_revert_pending_state_change(struct xe_guc *guc, if (pending_enable && !pending_resume && !exec_queue_pending_tdr_exit(q)) { clear_exec_queue_registered(q); - if (xe_exec_queue_is_lr(q)) - xe_exec_queue_put(q); xe_gt_dbg(guc_to_gt(guc), "Replay REGISTER - guc_id=%d", q->guc->id); } @@ -2560,10 +2458,7 @@ static void guc_exec_queue_pause(struct xe_guc *guc, struct xe_exec_queue *q) /* Stop scheduling + flush any DRM scheduler operations */ xe_sched_submission_stop(sched); - if (xe_exec_queue_is_lr(q)) - cancel_work_sync(&q->guc->lr_tdr); - else - cancel_delayed_work_sync(&sched->base.work_tdr); + cancel_delayed_work_sync(&sched->base.work_tdr); guc_exec_queue_revert_pending_state_change(guc, q); @@ -2986,11 +2881,7 @@ static void handle_deregister_done(struct xe_guc *guc, struct xe_exec_queue *q) trace_xe_exec_queue_deregister_done(q); clear_exec_queue_registered(q); - - if (xe_exec_queue_is_lr(q)) - xe_exec_queue_put(q); - else - __guc_exec_queue_destroy(guc, q); + __guc_exec_queue_destroy(guc, q); } int xe_guc_deregister_done_handler(struct xe_guc *guc, u32 *msg, u32 len) diff --git a/drivers/gpu/drm/xe/xe_trace.h b/drivers/gpu/drm/xe/xe_trace.h index 6d12fcc13f43..750fa32c13b2 100644 --- a/drivers/gpu/drm/xe/xe_trace.h +++ b/drivers/gpu/drm/xe/xe_trace.h @@ -228,11 +228,6 @@ DEFINE_EVENT(xe_exec_queue, xe_exec_queue_resubmit, TP_ARGS(q) ); -DEFINE_EVENT(xe_exec_queue, xe_exec_queue_lr_cleanup, - TP_PROTO(struct xe_exec_queue *q), - TP_ARGS(q) -); - DECLARE_EVENT_CLASS(xe_sched_job, TP_PROTO(struct xe_sched_job *job), TP_ARGS(job), -- cgit v1.2.3 From efffd56e4bd894e0935eea00e437f233b6cebc0d Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Fri, 9 Jan 2026 17:27:38 -0800 Subject: drm/xe: Disable timestamp WA on VFs The timestamp WA does not work on a VF because it requires reading MMIO registers, which are inaccessible on a VF. This timestamp WA confuses LRC sampling on a VF during TDR, as the LRC timestamp would always read as 1 for any active context. Disable the timestamp WA on VFs to avoid this confusion. Signed-off-by: Matthew Brost Reviewed-by: Umesh Nerlige Ramappa Fixes: 617d824c5323 ("drm/xe: Add WA BB to capture active context utilization") Link: https://patch.msgid.link/20260110012739.2888434-7-matthew.brost@intel.com --- drivers/gpu/drm/xe/xe_lrc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c index 70eae7d03a27..bf27fc9eebd3 100644 --- a/drivers/gpu/drm/xe/xe_lrc.c +++ b/drivers/gpu/drm/xe/xe_lrc.c @@ -1068,6 +1068,9 @@ static ssize_t setup_utilization_wa(struct xe_lrc *lrc, { u32 *cmd = batch; + if (IS_SRIOV_VF(gt_to_xe(lrc->gt))) + return 0; + if (xe_gt_WARN_ON(lrc->gt, max_len < 12)) return -ENOSPC; -- cgit v1.2.3 From bb63e7257e6341aa1e48da07b13d2d00fd899fb3 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Fri, 9 Jan 2026 17:27:39 -0800 Subject: drm/xe: Avoid toggling schedule state to check LRC timestamp in TDR We now have proper infrastructure to accurately check the LRC timestamp without toggling the scheduling state for non-VFs. For VFs, it is still possible to get an inaccurate view if the context is on hardware. We guard against free-running contexts on VFs by banning jobs whose timestamps are not moving. In addition, VFs have a timeslice quantum that naturally triggers context switches when more than one VF is running, thus updating the LRC timestamp. For multi-queue, it is desirable to avoid scheduling toggling in the TDR because this scheduling state is shared among many queues. Furthermore, this change simplifies the GuC state machine. The trade-off for VF cases seems worthwhile. v5: - Add xe_lrc_timestamp helper (Umesh) v6: - Reduce number of tries on stuck timestamp (VF testing) - Convert job timestamp save to a memory copy (VF testing) v7: - Save ctx timestamp to LRC when start VF job (VF testing) Signed-off-by: Matthew Brost Reviewed-by: Umesh Nerlige Ramappa Link: https://patch.msgid.link/20260110012739.2888434-8-matthew.brost@intel.com --- drivers/gpu/drm/xe/xe_guc_submit.c | 101 ++++++++------------------------ drivers/gpu/drm/xe/xe_lrc.c | 42 ++++++++----- drivers/gpu/drm/xe/xe_lrc.h | 3 +- drivers/gpu/drm/xe/xe_ring_ops.c | 25 ++++++-- drivers/gpu/drm/xe/xe_sched_job.c | 1 + drivers/gpu/drm/xe/xe_sched_job_types.h | 2 + 6 files changed, 78 insertions(+), 96 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index 1ddf465698ee..be8fa76baf1d 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -71,10 +71,8 @@ exec_queue_to_guc(struct xe_exec_queue *q) #define EXEC_QUEUE_STATE_KILLED (1 << 7) #define EXEC_QUEUE_STATE_WEDGED (1 << 8) #define EXEC_QUEUE_STATE_BANNED (1 << 9) -#define EXEC_QUEUE_STATE_CHECK_TIMEOUT (1 << 10) -#define EXEC_QUEUE_STATE_PENDING_RESUME (1 << 11) -#define EXEC_QUEUE_STATE_PENDING_TDR_EXIT (1 << 12) -#define EXEC_QUEUE_STATE_IDLE_SKIP_SUSPEND (1 << 13) +#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) { @@ -206,21 +204,6 @@ static void set_exec_queue_wedged(struct xe_exec_queue *q) atomic_or(EXEC_QUEUE_STATE_WEDGED, &q->guc->state); } -static bool exec_queue_check_timeout(struct xe_exec_queue *q) -{ - return atomic_read(&q->guc->state) & EXEC_QUEUE_STATE_CHECK_TIMEOUT; -} - -static void set_exec_queue_check_timeout(struct xe_exec_queue *q) -{ - atomic_or(EXEC_QUEUE_STATE_CHECK_TIMEOUT, &q->guc->state); -} - -static void clear_exec_queue_check_timeout(struct xe_exec_queue *q) -{ - atomic_and(~EXEC_QUEUE_STATE_CHECK_TIMEOUT, &q->guc->state); -} - static bool exec_queue_pending_resume(struct xe_exec_queue *q) { return atomic_read(&q->guc->state) & EXEC_QUEUE_STATE_PENDING_RESUME; @@ -236,21 +219,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_pending_tdr_exit(struct xe_exec_queue *q) -{ - return atomic_read(&q->guc->state) & EXEC_QUEUE_STATE_PENDING_TDR_EXIT; -} - -static void set_exec_queue_pending_tdr_exit(struct xe_exec_queue *q) -{ - atomic_or(EXEC_QUEUE_STATE_PENDING_TDR_EXIT, &q->guc->state); -} - -static void clear_exec_queue_pending_tdr_exit(struct xe_exec_queue *q) -{ - atomic_and(~EXEC_QUEUE_STATE_PENDING_TDR_EXIT, &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; @@ -620,19 +588,19 @@ static void xe_guc_exec_queue_reset_trigger_cleanup(struct xe_exec_queue *q) WRITE_ONCE(group->banned, true); set_exec_queue_reset(primary); - if (!exec_queue_banned(primary) && !exec_queue_check_timeout(primary)) + if (!exec_queue_banned(primary)) xe_guc_exec_queue_trigger_cleanup(primary); mutex_lock(&group->list_lock); list_for_each_entry(eq, &group->list, multi_queue.link) { set_exec_queue_reset(eq); - if (!exec_queue_banned(eq) && !exec_queue_check_timeout(eq)) + if (!exec_queue_banned(eq)) xe_guc_exec_queue_trigger_cleanup(eq); } mutex_unlock(&group->list_lock); } else { set_exec_queue_reset(q); - if (!exec_queue_banned(q) && !exec_queue_check_timeout(q)) + if (!exec_queue_banned(q)) xe_guc_exec_queue_trigger_cleanup(q); } } @@ -1349,7 +1317,16 @@ static bool check_timeout(struct xe_exec_queue *q, struct xe_sched_job *job) return xe_sched_invalidate_job(job, 2); } - ctx_timestamp = lower_32_bits(xe_lrc_ctx_timestamp(q->lrc[0])); + ctx_timestamp = lower_32_bits(xe_lrc_timestamp(q->lrc[0])); + if (ctx_timestamp == job->sample_timestamp) { + xe_gt_warn(gt, "Check job timeout: seqno=%u, lrc_seqno=%u, guc_id=%d, timestamp stuck", + xe_sched_job_seqno(job), xe_sched_job_lrc_seqno(job), + q->guc->id); + + return xe_sched_invalidate_job(job, 0); + } + + job->sample_timestamp = ctx_timestamp; ctx_job_timestamp = xe_lrc_ctx_job_timestamp(q->lrc[0]); /* @@ -1494,16 +1471,17 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) } /* - * XXX: Sampling timeout doesn't work in wedged mode as we have to - * modify scheduling state to read timestamp. We could read the - * timestamp from a register to accumulate current running time but this - * doesn't work for SRIOV. For now assuming timeouts in wedged mode are - * genuine timeouts. + * Check if job is actually timed out, if so restart job execution and TDR */ + if (!skip_timeout_check && !check_timeout(q, job)) + goto rearm; + if (!exec_queue_killed(q)) wedged = guc_submit_hint_wedged(exec_queue_to_guc(q)); - /* Engine state now stable, disable scheduling to check timestamp */ + set_exec_queue_banned(q); + + /* Kick job / queue off hardware */ if (!wedged && (exec_queue_enabled(q) || exec_queue_pending_disable(q))) { int ret; @@ -1525,13 +1503,6 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) if (!ret || xe_guc_read_stopped(guc)) goto trigger_reset; - /* - * Flag communicates to G2H handler that schedule - * disable originated from a timeout check. The G2H then - * avoid triggering cleanup or deregistering the exec - * queue. - */ - set_exec_queue_check_timeout(q); disable_scheduling(q, skip_timeout_check); } @@ -1560,22 +1531,12 @@ trigger_reset: xe_devcoredump(q, job, "Schedule disable failed to respond, guc_id=%d, ret=%d, guc_read=%d", q->guc->id, ret, xe_guc_read_stopped(guc)); - set_exec_queue_banned(q); xe_gt_reset_async(q->gt); xe_sched_tdr_queue_imm(sched); goto rearm; } } - /* - * Check if job is actually timed out, if so restart job execution and TDR - */ - if (!wedged && !skip_timeout_check && !check_timeout(q, job) && - !exec_queue_reset(q) && exec_queue_registered(q)) { - clear_exec_queue_check_timeout(q); - goto sched_enable; - } - if (q->vm && q->vm->xef) { process_name = q->vm->xef->process_name; pid = q->vm->xef->pid; @@ -1606,14 +1567,11 @@ trigger_reset: 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)) { - clear_exec_queue_check_timeout(q); xe_gt_reset_async(q->gt); goto rearm; } } - set_exec_queue_banned(q); - /* Mark all outstanding jobs as bad, thus completing them */ xe_sched_job_set_error(job, err); drm_sched_for_each_pending_job(tmp_job, &sched->base, NULL) @@ -1632,9 +1590,6 @@ trigger_reset: */ return DRM_GPU_SCHED_STAT_NO_HANG; -sched_enable: - set_exec_queue_pending_tdr_exit(q); - enable_scheduling(q); rearm: /* * XXX: Ideally want to adjust timeout based on current execution time @@ -2387,8 +2342,7 @@ static void guc_exec_queue_revert_pending_state_change(struct xe_guc *guc, q->guc->id); } - if (pending_enable && !pending_resume && - !exec_queue_pending_tdr_exit(q)) { + if (pending_enable && !pending_resume) { clear_exec_queue_registered(q); xe_gt_dbg(guc_to_gt(guc), "Replay REGISTER - guc_id=%d", q->guc->id); @@ -2397,7 +2351,6 @@ static void guc_exec_queue_revert_pending_state_change(struct xe_guc *guc, if (pending_enable) { clear_exec_queue_enabled(q); clear_exec_queue_pending_resume(q); - clear_exec_queue_pending_tdr_exit(q); clear_exec_queue_pending_enable(q); xe_gt_dbg(guc_to_gt(guc), "Replay ENABLE - guc_id=%d", q->guc->id); @@ -2423,7 +2376,6 @@ static void guc_exec_queue_revert_pending_state_change(struct xe_guc *guc, if (!pending_enable) set_exec_queue_enabled(q); clear_exec_queue_pending_disable(q); - clear_exec_queue_check_timeout(q); xe_gt_dbg(guc_to_gt(guc), "Replay DISABLE - guc_id=%d", q->guc->id); } @@ -2800,13 +2752,10 @@ static void handle_sched_done(struct xe_guc *guc, struct xe_exec_queue *q, q->guc->resume_time = ktime_get(); clear_exec_queue_pending_resume(q); - clear_exec_queue_pending_tdr_exit(q); clear_exec_queue_pending_enable(q); smp_wmb(); wake_up_all(&guc->ct.wq); } else { - bool check_timeout = exec_queue_check_timeout(q); - xe_gt_assert(guc_to_gt(guc), runnable_state == 0); xe_gt_assert(guc_to_gt(guc), exec_queue_pending_disable(q)); @@ -2814,11 +2763,11 @@ static void handle_sched_done(struct xe_guc *guc, struct xe_exec_queue *q, suspend_fence_signal(q); clear_exec_queue_pending_disable(q); } else { - if (exec_queue_banned(q) || check_timeout) { + if (exec_queue_banned(q)) { smp_wmb(); wake_up_all(&guc->ct.wq); } - if (!check_timeout && exec_queue_destroyed(q)) { + if (exec_queue_destroyed(q)) { /* * Make sure to clear the pending_disable only * after sampling the destroyed state. We want diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c index bf27fc9eebd3..f4f31bc240d9 100644 --- a/drivers/gpu/drm/xe/xe_lrc.c +++ b/drivers/gpu/drm/xe/xe_lrc.c @@ -857,7 +857,7 @@ u32 xe_lrc_ctx_timestamp_udw_ggtt_addr(struct xe_lrc *lrc) * * Returns: ctx timestamp value */ -u64 xe_lrc_ctx_timestamp(struct xe_lrc *lrc) +static u64 xe_lrc_ctx_timestamp(struct xe_lrc *lrc) { struct xe_device *xe = lrc_to_xe(lrc); struct iosys_map map; @@ -2409,35 +2409,31 @@ static int get_ctx_timestamp(struct xe_lrc *lrc, u32 engine_id, u64 *reg_ctx_ts) } /** - * xe_lrc_update_timestamp() - Update ctx timestamp + * xe_lrc_timestamp() - Current ctx timestamp * @lrc: Pointer to the lrc. - * @old_ts: Old timestamp value * - * Populate @old_ts current saved ctx timestamp, read new ctx timestamp and - * update saved value. With support for active contexts, the calculation may be - * slightly racy, so follow a read-again logic to ensure that the context is - * still active before returning the right timestamp. + * Return latest ctx timestamp. With support for active contexts, the + * calculation may bb slightly racy, so follow a read-again logic to ensure that + * the context is still active before returning the right timestamp. * * Returns: New ctx timestamp value */ -u64 xe_lrc_update_timestamp(struct xe_lrc *lrc, u64 *old_ts) +u64 xe_lrc_timestamp(struct xe_lrc *lrc) { - u64 lrc_ts, reg_ts; + u64 lrc_ts, reg_ts, new_ts; u32 engine_id; - *old_ts = lrc->ctx_timestamp; - lrc_ts = xe_lrc_ctx_timestamp(lrc); /* CTX_TIMESTAMP mmio read is invalid on VF, so return the LRC value */ if (IS_SRIOV_VF(lrc_to_xe(lrc))) { - lrc->ctx_timestamp = lrc_ts; + new_ts = lrc_ts; goto done; } if (lrc_ts == CONTEXT_ACTIVE) { engine_id = xe_lrc_engine_id(lrc); if (!get_ctx_timestamp(lrc, engine_id, ®_ts)) - lrc->ctx_timestamp = reg_ts; + new_ts = reg_ts; /* read lrc again to ensure context is still active */ lrc_ts = xe_lrc_ctx_timestamp(lrc); @@ -2448,9 +2444,27 @@ u64 xe_lrc_update_timestamp(struct xe_lrc *lrc, u64 *old_ts) * be a separate if condition. */ if (lrc_ts != CONTEXT_ACTIVE) - lrc->ctx_timestamp = lrc_ts; + new_ts = lrc_ts; done: + return new_ts; +} + +/** + * xe_lrc_update_timestamp() - Update ctx timestamp + * @lrc: Pointer to the lrc. + * @old_ts: Old timestamp value + * + * Populate @old_ts current saved ctx timestamp, read new ctx timestamp and + * update saved value. + * + * Returns: New ctx timestamp value + */ +u64 xe_lrc_update_timestamp(struct xe_lrc *lrc, u64 *old_ts) +{ + *old_ts = lrc->ctx_timestamp; + lrc->ctx_timestamp = xe_lrc_timestamp(lrc); + trace_xe_lrc_update_timestamp(lrc, *old_ts); return lrc->ctx_timestamp; diff --git a/drivers/gpu/drm/xe/xe_lrc.h b/drivers/gpu/drm/xe/xe_lrc.h index 8acf85273c1a..c307a3fd9ea2 100644 --- a/drivers/gpu/drm/xe/xe_lrc.h +++ b/drivers/gpu/drm/xe/xe_lrc.h @@ -145,7 +145,6 @@ void xe_lrc_snapshot_free(struct xe_lrc_snapshot *snapshot); u32 xe_lrc_ctx_timestamp_ggtt_addr(struct xe_lrc *lrc); u32 xe_lrc_ctx_timestamp_udw_ggtt_addr(struct xe_lrc *lrc); -u64 xe_lrc_ctx_timestamp(struct xe_lrc *lrc); u32 xe_lrc_ctx_job_timestamp_ggtt_addr(struct xe_lrc *lrc); u32 xe_lrc_ctx_job_timestamp(struct xe_lrc *lrc); int xe_lrc_setup_wa_bb_with_scratch(struct xe_lrc *lrc, struct xe_hw_engine *hwe, @@ -165,4 +164,6 @@ int xe_lrc_setup_wa_bb_with_scratch(struct xe_lrc *lrc, struct xe_hw_engine *hwe */ u64 xe_lrc_update_timestamp(struct xe_lrc *lrc, u64 *old_ts); +u64 xe_lrc_timestamp(struct xe_lrc *lrc); + #endif diff --git a/drivers/gpu/drm/xe/xe_ring_ops.c b/drivers/gpu/drm/xe/xe_ring_ops.c index 957b9e2fd138..a1fd99f2d539 100644 --- a/drivers/gpu/drm/xe/xe_ring_ops.c +++ b/drivers/gpu/drm/xe/xe_ring_ops.c @@ -235,13 +235,26 @@ static u32 get_ppgtt_flag(struct xe_sched_job *job) return 0; } -static int emit_copy_timestamp(struct xe_lrc *lrc, u32 *dw, int i) +static int emit_copy_timestamp(struct xe_device *xe, struct xe_lrc *lrc, + u32 *dw, int i) { dw[i++] = MI_STORE_REGISTER_MEM | MI_SRM_USE_GGTT | MI_SRM_ADD_CS_OFFSET; dw[i++] = RING_CTX_TIMESTAMP(0).addr; dw[i++] = xe_lrc_ctx_job_timestamp_ggtt_addr(lrc); dw[i++] = 0; + /* + * Ensure CTX timestamp >= Job timestamp during VF sampling to avoid + * arithmetic wraparound in TDR. + */ + if (IS_SRIOV_VF(xe)) { + dw[i++] = MI_STORE_REGISTER_MEM | MI_SRM_USE_GGTT | + MI_SRM_ADD_CS_OFFSET; + dw[i++] = RING_CTX_TIMESTAMP(0).addr; + dw[i++] = xe_lrc_ctx_timestamp_ggtt_addr(lrc); + dw[i++] = 0; + } + return i; } @@ -255,7 +268,7 @@ static void __emit_job_gen12_simple(struct xe_sched_job *job, struct xe_lrc *lrc *head = lrc->ring.tail; - i = emit_copy_timestamp(lrc, dw, i); + i = emit_copy_timestamp(gt_to_xe(gt), lrc, dw, i); if (job->ring_ops_flush_tlb) { dw[i++] = preparser_disable(true); @@ -310,7 +323,7 @@ static void __emit_job_gen12_video(struct xe_sched_job *job, struct xe_lrc *lrc, *head = lrc->ring.tail; - i = emit_copy_timestamp(lrc, dw, i); + i = emit_copy_timestamp(xe, lrc, dw, i); dw[i++] = preparser_disable(true); @@ -364,7 +377,7 @@ static void __emit_job_gen12_render_compute(struct xe_sched_job *job, *head = lrc->ring.tail; - i = emit_copy_timestamp(lrc, dw, i); + i = emit_copy_timestamp(xe, lrc, dw, i); dw[i++] = preparser_disable(true); if (lacks_render) @@ -406,12 +419,14 @@ static void emit_migration_job_gen12(struct xe_sched_job *job, struct xe_lrc *lrc, u32 *head, u32 seqno) { + struct xe_gt *gt = job->q->gt; + struct xe_device *xe = gt_to_xe(gt); u32 saddr = xe_lrc_start_seqno_ggtt_addr(lrc); u32 dw[MAX_JOB_SIZE_DW], i = 0; *head = lrc->ring.tail; - i = emit_copy_timestamp(lrc, dw, i); + i = emit_copy_timestamp(xe, lrc, dw, i); i = emit_store_imm_ggtt(saddr, seqno, dw, i); diff --git a/drivers/gpu/drm/xe/xe_sched_job.c b/drivers/gpu/drm/xe/xe_sched_job.c index cb674a322113..39aec7f6d86d 100644 --- a/drivers/gpu/drm/xe/xe_sched_job.c +++ b/drivers/gpu/drm/xe/xe_sched_job.c @@ -110,6 +110,7 @@ struct xe_sched_job *xe_sched_job_create(struct xe_exec_queue *q, return ERR_PTR(-ENOMEM); job->q = q; + job->sample_timestamp = U64_MAX; kref_init(&job->refcount); xe_exec_queue_get(job->q); diff --git a/drivers/gpu/drm/xe/xe_sched_job_types.h b/drivers/gpu/drm/xe/xe_sched_job_types.h index 7c4c54fe920a..13c2970e81a8 100644 --- a/drivers/gpu/drm/xe/xe_sched_job_types.h +++ b/drivers/gpu/drm/xe/xe_sched_job_types.h @@ -59,6 +59,8 @@ struct xe_sched_job { u32 lrc_seqno; /** @migrate_flush_flags: Additional flush flags for migration jobs */ u32 migrate_flush_flags; + /** @sample_timestamp: Sampling of job timestamp in TDR */ + u64 sample_timestamp; /** @ring_ops_flush_tlb: The ring ops need to flush TLB before payload. */ bool ring_ops_flush_tlb; /** @ggtt: mapped in ggtt. */ -- cgit v1.2.3 From e7994954c2bea9e754c5da546846fb1cd79f5151 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 9 Jan 2026 16:12:15 +0100 Subject: drm/xe/mert: Normalize xe_mert.h include guards Most of our header files are using include guard names with single underscore and we don't use trailing comments on final #endif. Signed-off-by: Michal Wajdeczko Cc: Lukasz Laguna Reviewed-by: Lukasz Laguna Link: https://patch.msgid.link/20260109151219.26206-2-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_mert.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_mert.h b/drivers/gpu/drm/xe/xe_mert.h index 2e14c5dec008..0de8243e46bd 100644 --- a/drivers/gpu/drm/xe/xe_mert.h +++ b/drivers/gpu/drm/xe/xe_mert.h @@ -3,8 +3,8 @@ * Copyright(c) 2025, Intel Corporation. All rights reserved. */ -#ifndef __XE_MERT_H__ -#define __XE_MERT_H__ +#ifndef _XE_MERT_H_ +#define _XE_MERT_H_ #include #include @@ -29,4 +29,4 @@ void xe_mert_irq_handler(struct xe_device *xe, u32 master_ctl); static inline void xe_mert_irq_handler(struct xe_device *xe, u32 master_ctl) { } #endif -#endif /* __XE_MERT_H__ */ +#endif -- cgit v1.2.3 From a92c68eb1e19de9ea8de6c7d3bcfff6c3fcb3c10 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 9 Jan 2026 16:12:16 +0100 Subject: drm/xe/mert: Fix kernel-doc for struct xe_mert Add simple top level kernel-doc for the struct itself to allow the script recognize that and fix tag of the one member. Signed-off-by: Michal Wajdeczko Cc: Lukasz Laguna Reviewed-by: Lukasz Laguna Link: https://patch.msgid.link/20260109151219.26206-3-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_mert.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_mert.h b/drivers/gpu/drm/xe/xe_mert.h index 0de8243e46bd..0e27f9fa24bb 100644 --- a/drivers/gpu/drm/xe/xe_mert.h +++ b/drivers/gpu/drm/xe/xe_mert.h @@ -13,12 +13,15 @@ struct xe_device; struct xe_tile; +/** + * struct xe_mert - MERT related data + */ struct xe_mert { /** @lock: protects the TLB invalidation status */ spinlock_t lock; /** @tlb_inv_triggered: indicates if TLB invalidation was triggered */ bool tlb_inv_triggered; - /** @mert.tlb_inv_done: completion of TLB invalidation */ + /** @tlb_inv_done: completion of TLB invalidation */ struct completion tlb_inv_done; }; -- cgit v1.2.3 From ff4eca1f46f3c2c485055e2c31432ab1ec5dbb96 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Sun, 11 Jan 2026 22:38:47 +0100 Subject: drm/xe/mert: Always refer to MERT using xe_device There is only one MERT instance and while it is located on the root tile, it is safer to refer to it using xe_device rather than xe_tile. This will also allow to align signature with other MERT function. Signed-off-by: Michal Wajdeczko Cc: Lukasz Laguna Reviewed-by: Lukasz Laguna Link: https://patch.msgid.link/20260111213847.27869-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_lmtt.c | 2 +- drivers/gpu/drm/xe/xe_mert.c | 9 ++++----- drivers/gpu/drm/xe/xe_mert.h | 3 +-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_lmtt.c b/drivers/gpu/drm/xe/xe_lmtt.c index 3059ea6525bc..2077e1ef8b43 100644 --- a/drivers/gpu/drm/xe/xe_lmtt.c +++ b/drivers/gpu/drm/xe/xe_lmtt.c @@ -289,7 +289,7 @@ void xe_lmtt_invalidate_hw(struct xe_lmtt *lmtt) ERR_PTR(err)); if (xe_device_has_mert(xe) && xe_tile_is_root(tile)) { - err = xe_mert_invalidate_lmtt(tile); + err = xe_mert_invalidate_lmtt(xe); if (err) xe_tile_sriov_err(tile, "MERT LMTT invalidation failed (%pe)", ERR_PTR(err)); diff --git a/drivers/gpu/drm/xe/xe_mert.c b/drivers/gpu/drm/xe/xe_mert.c index f7689e922953..598b039dfe25 100644 --- a/drivers/gpu/drm/xe/xe_mert.c +++ b/drivers/gpu/drm/xe/xe_mert.c @@ -12,22 +12,21 @@ #include "xe_tile.h" /** - * xe_mert_invalidate_lmtt - Invalidate MERT LMTT - * @tile: the &xe_tile + * xe_mert_invalidate_lmtt() - Invalidate MERT LMTT + * @xe: the &xe_device with MERT * * Trigger invalidation of the MERT LMTT and wait for completion. * * Return: 0 on success or -ETIMEDOUT in case of a timeout. */ -int xe_mert_invalidate_lmtt(struct xe_tile *tile) +int xe_mert_invalidate_lmtt(struct xe_device *xe) { - struct xe_device *xe = tile_to_xe(tile); + struct xe_tile *tile = xe_device_get_root_tile(xe); struct xe_mert *mert = &tile->mert; const long timeout = HZ / 4; unsigned long flags; xe_assert(xe, xe_device_has_mert(xe)); - xe_assert(xe, xe_tile_is_root(tile)); spin_lock_irqsave(&mert->lock, flags); if (!mert->tlb_inv_triggered) { diff --git a/drivers/gpu/drm/xe/xe_mert.h b/drivers/gpu/drm/xe/xe_mert.h index 0e27f9fa24bb..44daeca094bd 100644 --- a/drivers/gpu/drm/xe/xe_mert.h +++ b/drivers/gpu/drm/xe/xe_mert.h @@ -11,7 +11,6 @@ #include struct xe_device; -struct xe_tile; /** * struct xe_mert - MERT related data @@ -26,7 +25,7 @@ struct xe_mert { }; #ifdef CONFIG_PCI_IOV -int xe_mert_invalidate_lmtt(struct xe_tile *tile); +int xe_mert_invalidate_lmtt(struct xe_device *xe); void xe_mert_irq_handler(struct xe_device *xe, u32 master_ctl); #else static inline void xe_mert_irq_handler(struct xe_device *xe, u32 master_ctl) { } -- cgit v1.2.3 From 401fabd6e2767e92cb5b23ec38948cec1d52c754 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 9 Jan 2026 16:12:18 +0100 Subject: drm/xe/mert: Use local mert variable to simplify the code There is no need to always refer to MERT data using tile pointer. Use of local mert pointer will simplify the code and make it look like other existing MERT function. Signed-off-by: Michal Wajdeczko Cc: Lukasz Laguna Reviewed-by: Lukasz Laguna Link: https://patch.msgid.link/20260109151219.26206-5-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_mert.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_mert.c b/drivers/gpu/drm/xe/xe_mert.c index 598b039dfe25..ad832e89256c 100644 --- a/drivers/gpu/drm/xe/xe_mert.c +++ b/drivers/gpu/drm/xe/xe_mert.c @@ -52,6 +52,7 @@ int xe_mert_invalidate_lmtt(struct xe_device *xe) void xe_mert_irq_handler(struct xe_device *xe, u32 master_ctl) { struct xe_tile *tile = xe_device_get_root_tile(xe); + struct xe_mert *mert = &tile->mert; unsigned long flags; u32 reg_val; u8 err; @@ -69,13 +70,13 @@ void xe_mert_irq_handler(struct xe_device *xe, u32 master_ctl) else if (err) drm_dbg(&xe->drm, "MERT catastrophic error: Unexpected fault (0x%x)\n", err); - spin_lock_irqsave(&tile->mert.lock, flags); - if (tile->mert.tlb_inv_triggered) { + spin_lock_irqsave(&mert->lock, flags); + if (mert->tlb_inv_triggered) { reg_val = xe_mmio_read32(&tile->mmio, MERT_TLB_INV_DESC_A); if (!(reg_val & MERT_TLB_INV_DESC_A_VALID)) { - tile->mert.tlb_inv_triggered = false; - complete_all(&tile->mert.tlb_inv_done); + mert->tlb_inv_triggered = false; + complete_all(&mert->tlb_inv_done); } } - spin_unlock_irqrestore(&tile->mert.lock, flags); + spin_unlock_irqrestore(&mert->lock, flags); } -- cgit v1.2.3 From 7970e04d1705075e01f1e168e5b32c9c7680118b Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 9 Jan 2026 16:12:19 +0100 Subject: drm/xe/mert: Move MERT initialization to xe_mert.c Most of the MERT code is already in dedicated file, no reason to keep internal MERT data structure initialization elsewhere. Signed-off-by: Michal Wajdeczko Cc: Lukasz Laguna Reviewed-by: Lukasz Laguna Link: https://patch.msgid.link/20260109151219.26206-6-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_mert.c | 13 +++++++++++++ drivers/gpu/drm/xe/xe_mert.h | 1 + drivers/gpu/drm/xe/xe_sriov_pf.c | 4 +--- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_mert.c b/drivers/gpu/drm/xe/xe_mert.c index ad832e89256c..fc027d2d7a5e 100644 --- a/drivers/gpu/drm/xe/xe_mert.c +++ b/drivers/gpu/drm/xe/xe_mert.c @@ -11,6 +11,19 @@ #include "xe_mmio.h" #include "xe_tile.h" +/** + * xe_mert_init_early() - Initialize MERT data + * @xe: the &xe_device with MERT to init + */ +void xe_mert_init_early(struct xe_device *xe) +{ + struct xe_tile *tile = xe_device_get_root_tile(xe); + struct xe_mert *mert = &tile->mert; + + spin_lock_init(&mert->lock); + init_completion(&mert->tlb_inv_done); +} + /** * xe_mert_invalidate_lmtt() - Invalidate MERT LMTT * @xe: the &xe_device with MERT diff --git a/drivers/gpu/drm/xe/xe_mert.h b/drivers/gpu/drm/xe/xe_mert.h index 44daeca094bd..fc977203692d 100644 --- a/drivers/gpu/drm/xe/xe_mert.h +++ b/drivers/gpu/drm/xe/xe_mert.h @@ -25,6 +25,7 @@ struct xe_mert { }; #ifdef CONFIG_PCI_IOV +void xe_mert_init_early(struct xe_device *xe); int xe_mert_invalidate_lmtt(struct xe_device *xe); void xe_mert_irq_handler(struct xe_device *xe, u32 master_ctl); #else diff --git a/drivers/gpu/drm/xe/xe_sriov_pf.c b/drivers/gpu/drm/xe/xe_sriov_pf.c index 72423bb17e6f..6ce3c58e003c 100644 --- a/drivers/gpu/drm/xe/xe_sriov_pf.c +++ b/drivers/gpu/drm/xe/xe_sriov_pf.c @@ -90,7 +90,6 @@ bool xe_sriov_pf_readiness(struct xe_device *xe) */ int xe_sriov_pf_init_early(struct xe_device *xe) { - struct xe_mert *mert = &xe_device_get_root_tile(xe)->mert; int err; xe_assert(xe, IS_SRIOV_PF(xe)); @@ -112,8 +111,7 @@ int xe_sriov_pf_init_early(struct xe_device *xe) xe_sriov_pf_service_init(xe); - spin_lock_init(&mert->lock); - init_completion(&mert->tlb_inv_done); + xe_mert_init_early(xe); return 0; } -- cgit v1.2.3 From 22437f30d2f0265095eb1e14bf44d30e6663e676 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 8 Jan 2026 11:10:16 +0100 Subject: drm/xe: Start using ggtt->start in preparation of balloon removal Instead of having ggtt->size point to the end of ggtt, have ggtt->size be the actual size of the GGTT, and introduce ggtt->start to point to the beginning of GGTT. This will allow a massive cleanup of GGTT in case of SRIOV-VF. Reviewed-by: Stuart Summers Signed-off-by: Maarten Lankhorst Link: https://patch.msgid.link/20260108101014.579906-10-dev@lankhorst.se --- drivers/gpu/drm/xe/tests/xe_guc_buf_kunit.c | 2 +- drivers/gpu/drm/xe/xe_ggtt.c | 82 ++++++++++++++++++----------- drivers/gpu/drm/xe/xe_ggtt.h | 2 + drivers/gpu/drm/xe/xe_ggtt_types.h | 4 +- drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c | 4 +- 5 files changed, 60 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/xe/tests/xe_guc_buf_kunit.c b/drivers/gpu/drm/xe/tests/xe_guc_buf_kunit.c index d266882adc0e..acddbedcf17c 100644 --- a/drivers/gpu/drm/xe/tests/xe_guc_buf_kunit.c +++ b/drivers/gpu/drm/xe/tests/xe_guc_buf_kunit.c @@ -67,7 +67,7 @@ static int guc_buf_test_init(struct kunit *test) KUNIT_ASSERT_EQ(test, 0, xe_ggtt_init_kunit(ggtt, DUT_GGTT_START, - DUT_GGTT_START + DUT_GGTT_SIZE)); + DUT_GGTT_SIZE)); kunit_activate_static_stub(test, xe_managed_bo_create_pin_map, replacement_xe_managed_bo_create_pin_map); diff --git a/drivers/gpu/drm/xe/xe_ggtt.c b/drivers/gpu/drm/xe/xe_ggtt.c index 9e6b4e983542..73d3351f0181 100644 --- a/drivers/gpu/drm/xe/xe_ggtt.c +++ b/drivers/gpu/drm/xe/xe_ggtt.c @@ -137,10 +137,32 @@ static void ggtt_update_access_counter(struct xe_ggtt *ggtt) } } +/** + * xe_ggtt_start - Get starting offset of GGTT. + * @ggtt: &xe_ggtt + * + * Returns: Starting offset for this &xe_ggtt. + */ +u64 xe_ggtt_start(struct xe_ggtt *ggtt) +{ + return ggtt->start; +} + +/** + * xe_ggtt_size - Get size of GGTT. + * @ggtt: &xe_ggtt + * + * Returns: Total usable size of this &xe_ggtt. + */ +u64 xe_ggtt_size(struct xe_ggtt *ggtt) +{ + return ggtt->size; +} + static void xe_ggtt_set_pte(struct xe_ggtt *ggtt, u64 addr, u64 pte) { xe_tile_assert(ggtt->tile, !(addr & XE_PTE_MASK)); - xe_tile_assert(ggtt->tile, addr < ggtt->size); + xe_tile_assert(ggtt->tile, addr < ggtt->start + ggtt->size); writeq(pte, &ggtt->gsm[addr >> XE_PTE_SHIFT]); } @@ -256,16 +278,16 @@ static const struct xe_ggtt_pt_ops xelpg_pt_wa_ops = { .ggtt_get_pte = xe_ggtt_get_pte, }; -static void __xe_ggtt_init_early(struct xe_ggtt *ggtt, u32 reserved) +static void __xe_ggtt_init_early(struct xe_ggtt *ggtt, u64 start, u64 size) { - drm_mm_init(&ggtt->mm, reserved, - ggtt->size - reserved); + ggtt->start = start; + ggtt->size = size; + drm_mm_init(&ggtt->mm, start, size); } -int xe_ggtt_init_kunit(struct xe_ggtt *ggtt, u32 reserved, u32 size) +int xe_ggtt_init_kunit(struct xe_ggtt *ggtt, u32 start, u32 size) { - ggtt->size = size; - __xe_ggtt_init_early(ggtt, reserved); + __xe_ggtt_init_early(ggtt, start, size); return 0; } EXPORT_SYMBOL_IF_KUNIT(xe_ggtt_init_kunit); @@ -293,26 +315,32 @@ int xe_ggtt_init_early(struct xe_ggtt *ggtt) struct xe_device *xe = tile_to_xe(ggtt->tile); struct pci_dev *pdev = to_pci_dev(xe->drm.dev); unsigned int gsm_size; + u64 ggtt_start, wopcm = xe_wopcm_size(xe), ggtt_size; int err; - if (IS_SRIOV_VF(xe) || GRAPHICS_VERx100(xe) >= 1250) - gsm_size = SZ_8M; /* GGTT is expected to be 4GiB */ - else - gsm_size = probe_gsm_size(pdev); - - if (gsm_size == 0) { - xe_tile_err(ggtt->tile, "Hardware reported no preallocated GSM\n"); - return -ENOMEM; + if (!IS_SRIOV_VF(xe)) { + if (GRAPHICS_VERx100(xe) >= 1250) + gsm_size = SZ_8M; /* GGTT is expected to be 4GiB */ + else + gsm_size = probe_gsm_size(pdev); + if (gsm_size == 0) { + xe_tile_err(ggtt->tile, "Hardware reported no preallocated GSM\n"); + return -ENOMEM; + } + ggtt_start = wopcm; + ggtt_size = (gsm_size / 8) * (u64)XE_PAGE_SIZE - ggtt_start; + } else { + /* GGTT is expected to be 4GiB */ + ggtt_start = wopcm; + ggtt_size = SZ_4G - ggtt_start; } ggtt->gsm = ggtt->tile->mmio.regs + SZ_8M; - ggtt->size = (gsm_size / 8) * (u64) XE_PAGE_SIZE; - if (IS_DGFX(xe) && xe->info.vram_flags & XE_VRAM_FLAGS_NEED64K) ggtt->flags |= XE_GGTT_FLAGS_64K; - if (ggtt->size > GUC_GGTT_TOP) - ggtt->size = GUC_GGTT_TOP; + if (ggtt_size + ggtt_start > GUC_GGTT_TOP) + ggtt_size = GUC_GGTT_TOP - ggtt_start; if (GRAPHICS_VERx100(xe) >= 1270) ggtt->pt_ops = @@ -326,7 +354,7 @@ int xe_ggtt_init_early(struct xe_ggtt *ggtt) if (!ggtt->wq) return -ENOMEM; - __xe_ggtt_init_early(ggtt, xe_wopcm_size(xe)); + __xe_ggtt_init_early(ggtt, ggtt_start, ggtt_size); err = drmm_add_action_or_reset(&xe->drm, ggtt_fini_early, ggtt); if (err) @@ -563,11 +591,9 @@ void xe_ggtt_node_remove_balloon_locked(struct xe_ggtt_node *node) static void xe_ggtt_assert_fit(struct xe_ggtt *ggtt, u64 start, u64 size) { struct xe_tile *tile = ggtt->tile; - struct xe_device *xe = tile_to_xe(tile); - u64 __maybe_unused wopcm = xe_wopcm_size(xe); - xe_tile_assert(tile, start >= wopcm); - xe_tile_assert(tile, start + size < ggtt->size - wopcm); + xe_tile_assert(tile, start >= ggtt->start); + xe_tile_assert(tile, start + size <= ggtt->start + ggtt->size); } /** @@ -890,14 +916,12 @@ u64 xe_ggtt_largest_hole(struct xe_ggtt *ggtt, u64 alignment, u64 *spare) { const struct drm_mm *mm = &ggtt->mm; const struct drm_mm_node *entry; - u64 hole_min_start = xe_wopcm_size(tile_to_xe(ggtt->tile)); u64 hole_start, hole_end, hole_size; u64 max_hole = 0; mutex_lock(&ggtt->lock); - drm_mm_for_each_hole(entry, mm, hole_start, hole_end) { - hole_start = max(hole_start, hole_min_start); + hole_start = max(hole_start, ggtt->start); hole_start = ALIGN(hole_start, alignment); hole_end = ALIGN_DOWN(hole_end, alignment); if (hole_start >= hole_end) @@ -1069,15 +1093,13 @@ u64 xe_ggtt_print_holes(struct xe_ggtt *ggtt, u64 alignment, struct drm_printer { const struct drm_mm *mm = &ggtt->mm; const struct drm_mm_node *entry; - u64 hole_min_start = xe_wopcm_size(tile_to_xe(ggtt->tile)); u64 hole_start, hole_end, hole_size; u64 total = 0; char buf[10]; mutex_lock(&ggtt->lock); - drm_mm_for_each_hole(entry, mm, hole_start, hole_end) { - hole_start = max(hole_start, hole_min_start); + hole_start = max(hole_start, ggtt->start); hole_start = ALIGN(hole_start, alignment); hole_end = ALIGN_DOWN(hole_end, alignment); if (hole_start >= hole_end) diff --git a/drivers/gpu/drm/xe/xe_ggtt.h b/drivers/gpu/drm/xe/xe_ggtt.h index 93fea4b6079c..df7196ec4696 100644 --- a/drivers/gpu/drm/xe/xe_ggtt.h +++ b/drivers/gpu/drm/xe/xe_ggtt.h @@ -23,6 +23,8 @@ int xe_ggtt_node_insert_balloon_locked(struct xe_ggtt_node *node, u64 start, u64 size); void xe_ggtt_node_remove_balloon_locked(struct xe_ggtt_node *node); void xe_ggtt_shift_nodes_locked(struct xe_ggtt *ggtt, s64 shift); +u64 xe_ggtt_start(struct xe_ggtt *ggtt); +u64 xe_ggtt_size(struct xe_ggtt *ggtt); int xe_ggtt_node_insert(struct xe_ggtt_node *node, u32 size, u32 align); int xe_ggtt_node_insert_locked(struct xe_ggtt_node *node, diff --git a/drivers/gpu/drm/xe/xe_ggtt_types.h b/drivers/gpu/drm/xe/xe_ggtt_types.h index dacd796f8184..d773cf284c03 100644 --- a/drivers/gpu/drm/xe/xe_ggtt_types.h +++ b/drivers/gpu/drm/xe/xe_ggtt_types.h @@ -22,7 +22,9 @@ struct xe_gt; struct xe_ggtt { /** @tile: Back pointer to tile where this GGTT belongs */ struct xe_tile *tile; - /** @size: Total size of this GGTT */ + /** @start: Start offset of GGTT */ + u64 start; + /** @size: Total usable size of this GGTT */ u64 size; #define XE_GGTT_FLAGS_64K BIT(0) diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c index 5a870914b102..bed6580d8d09 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c @@ -393,8 +393,8 @@ static int pf_push_full_vf_config(struct xe_gt *gt, unsigned int vfid) xe_gt_assert(gt, num_dwords <= max_cfg_dwords); if (vfid == PFID) { - u64 ggtt_start = xe_wopcm_size(gt_to_xe(gt)); - u64 ggtt_size = gt_to_tile(gt)->mem.ggtt->size - ggtt_start; + u64 ggtt_start = xe_ggtt_start(gt_to_tile(gt)->mem.ggtt); + u64 ggtt_size = xe_ggtt_size(gt_to_tile(gt)->mem.ggtt); /* plain PF config data will never include a real GGTT region */ xe_gt_assert(gt, !encode_config_ggtt(cfg + num_dwords, config, true)); -- cgit v1.2.3 From 004311aa7d7ae1f591dff996232b15f2b480e93b Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 8 Jan 2026 11:10:17 +0100 Subject: drm/xe: Convert xe_fb_pin to use a callback for insertion into GGTT The rotation details belong in xe_fb_pin.c, while the operations involving GGTT belong to xe_ggtt.c. As directly locking xe_ggtt etc results in exposing all of xe_ggtt details anyway, create a special function that allocates a ggtt_node, and allow display to populate it using a callback as a compromise. Signed-off-by: Maarten Lankhorst Reviewed-by: Matthew Brost Reviewed-by: Juha-Pekka Heikkila Signed-off-by: Maarten Lankhorst Link: https://patch.msgid.link/20260108101014.579906-11-dev@lankhorst.se --- drivers/gpu/drm/xe/display/xe_fb_pin.c | 102 ++++++++++++++++----------------- drivers/gpu/drm/xe/xe_ggtt.c | 92 +++++++++++++++++++++-------- drivers/gpu/drm/xe/xe_ggtt.h | 9 +-- drivers/gpu/drm/xe/xe_ggtt_types.h | 9 ++- 4 files changed, 131 insertions(+), 81 deletions(-) diff --git a/drivers/gpu/drm/xe/display/xe_fb_pin.c b/drivers/gpu/drm/xe/display/xe_fb_pin.c index 6a935a75f2a4..c7c9c2e9c233 100644 --- a/drivers/gpu/drm/xe/display/xe_fb_pin.c +++ b/drivers/gpu/drm/xe/display/xe_fb_pin.c @@ -171,12 +171,13 @@ static int __xe_pin_fb_vma_dpt(const struct intel_framebuffer *fb, } static void -write_ggtt_rotated(struct xe_bo *bo, struct xe_ggtt *ggtt, u32 *ggtt_ofs, u32 bo_ofs, +write_ggtt_rotated(struct xe_ggtt *ggtt, u32 *ggtt_ofs, + u64 pte_flags, + xe_ggtt_set_pte_fn write_pte, + struct xe_bo *bo, u32 bo_ofs, u32 width, u32 height, u32 src_stride, u32 dst_stride) { - struct xe_device *xe = xe_bo_device(bo); u32 column, row; - u64 pte = ggtt->pt_ops->pte_encode_flags(bo, xe->pat.idx[XE_CACHE_NONE]); for (column = 0; column < width; column++) { u32 src_idx = src_stride * (height - 1) + column + bo_ofs; @@ -184,7 +185,7 @@ write_ggtt_rotated(struct xe_bo *bo, struct xe_ggtt *ggtt, u32 *ggtt_ofs, u32 bo for (row = 0; row < height; row++) { u64 addr = xe_bo_addr(bo, src_idx * XE_PAGE_SIZE, XE_PAGE_SIZE); - ggtt->pt_ops->ggtt_set_pte(ggtt, *ggtt_ofs, pte | addr); + write_pte(ggtt, *ggtt_ofs, pte_flags | addr); *ggtt_ofs += XE_PAGE_SIZE; src_idx -= src_stride; } @@ -194,6 +195,28 @@ write_ggtt_rotated(struct xe_bo *bo, struct xe_ggtt *ggtt, u32 *ggtt_ofs, u32 bo } } +struct fb_rotate_args { + const struct i915_gtt_view *view; + struct xe_bo *bo; +}; + +static void write_ggtt_rotated_node(struct xe_ggtt *ggtt, struct xe_ggtt_node *node, + u64 pte_flags, xe_ggtt_set_pte_fn write_pte, void *data) +{ + struct fb_rotate_args *args = data; + struct xe_bo *bo = args->bo; + const struct intel_rotation_info *rot_info = &args->view->rotated; + u32 ggtt_ofs = node->base.start; + + for (u32 i = 0; i < ARRAY_SIZE(rot_info->plane); i++) + write_ggtt_rotated(ggtt, &ggtt_ofs, pte_flags, write_pte, + bo, rot_info->plane[i].offset, + rot_info->plane[i].width, + rot_info->plane[i].height, + rot_info->plane[i].src_stride, + rot_info->plane[i].dst_stride); +} + static int __xe_pin_fb_vma_ggtt(const struct intel_framebuffer *fb, const struct i915_gtt_view *view, struct i915_vma *vma, @@ -204,66 +227,43 @@ static int __xe_pin_fb_vma_ggtt(const struct intel_framebuffer *fb, struct xe_device *xe = to_xe_device(fb->base.dev); struct xe_tile *tile0 = xe_device_get_root_tile(xe); struct xe_ggtt *ggtt = tile0->mem.ggtt; + u64 pte, size; u32 align; - int ret; + int ret = 0; /* TODO: Consider sharing framebuffer mapping? * embed i915_vma inside intel_framebuffer */ guard(xe_pm_runtime_noresume)(xe); - ACQUIRE(mutex_intr, lock)(&ggtt->lock); - ret = ACQUIRE_ERR(mutex_intr, &lock); - if (ret) - return ret; align = XE_PAGE_SIZE; - if (xe_bo_is_vram(bo) && ggtt->flags & XE_GGTT_FLAGS_64K) - align = max_t(u32, align, SZ_64K); + if (xe_bo_is_vram(bo) && xe->info.vram_flags & XE_VRAM_FLAGS_NEED64K) + align = max(align, SZ_64K); + /* Fast case, preallocated GGTT view? */ if (bo->ggtt_node[tile0->id] && view->type == I915_GTT_VIEW_NORMAL) { vma->node = bo->ggtt_node[tile0->id]; - } else if (view->type == I915_GTT_VIEW_NORMAL) { - vma->node = xe_ggtt_node_init(ggtt); - if (IS_ERR(vma->node)) - return PTR_ERR(vma->node); - - ret = xe_ggtt_node_insert_locked(vma->node, xe_bo_size(bo), align, 0); - if (ret) { - xe_ggtt_node_fini(vma->node); - return ret; - } - - xe_ggtt_map_bo(ggtt, vma->node, bo, xe->pat.idx[XE_CACHE_NONE]); - } else { - u32 i, ggtt_ofs; - const struct intel_rotation_info *rot_info = &view->rotated; - - /* display seems to use tiles instead of bytes here, so convert it back.. */ - u32 size = intel_rotation_info_size(rot_info) * XE_PAGE_SIZE; - - vma->node = xe_ggtt_node_init(ggtt); - if (IS_ERR(vma->node)) { - ret = PTR_ERR(vma->node); - return ret; - } - - ret = xe_ggtt_node_insert_locked(vma->node, size, align, 0); - if (ret) { - xe_ggtt_node_fini(vma->node); - return ret; - } - - ggtt_ofs = vma->node->base.start; - - for (i = 0; i < ARRAY_SIZE(rot_info->plane); i++) - write_ggtt_rotated(bo, ggtt, &ggtt_ofs, - rot_info->plane[i].offset, - rot_info->plane[i].width, - rot_info->plane[i].height, - rot_info->plane[i].src_stride, - rot_info->plane[i].dst_stride); + return 0; } + /* TODO: Consider sharing framebuffer mapping? + * embed i915_vma inside intel_framebuffer + */ + if (view->type == I915_GTT_VIEW_NORMAL) + size = xe_bo_size(bo); + else + /* display uses tiles instead of bytes here, so convert it back.. */ + size = intel_rotation_info_size(&view->rotated) * XE_PAGE_SIZE; + + pte = xe_ggtt_encode_pte_flags(ggtt, bo, xe->pat.idx[XE_CACHE_NONE]); + vma->node = xe_ggtt_node_insert_transform(ggtt, bo, pte, + ALIGN(size, align), align, + view->type == I915_GTT_VIEW_NORMAL ? + NULL : write_ggtt_rotated_node, + &(struct fb_rotate_args){view, bo}); + if (IS_ERR(vma->node)) + ret = PTR_ERR(vma->node); + return ret; } diff --git a/drivers/gpu/drm/xe/xe_ggtt.c b/drivers/gpu/drm/xe/xe_ggtt.c index 73d3351f0181..2bd386b0f7b9 100644 --- a/drivers/gpu/drm/xe/xe_ggtt.c +++ b/drivers/gpu/drm/xe/xe_ggtt.c @@ -636,20 +636,8 @@ void xe_ggtt_shift_nodes_locked(struct xe_ggtt *ggtt, s64 shift) } } -/** - * xe_ggtt_node_insert_locked - Locked version to insert a &xe_ggtt_node into the GGTT - * @node: the &xe_ggtt_node to be inserted - * @size: size of the node - * @align: alignment constrain of the node - * @mm_flags: flags to control the node behavior - * - * It cannot be called without first having called xe_ggtt_init() once. - * To be used in cases where ggtt->lock is already taken. - * - * Return: 0 on success or a negative error code on failure. - */ -int xe_ggtt_node_insert_locked(struct xe_ggtt_node *node, - u32 size, u32 align, u32 mm_flags) +static int xe_ggtt_node_insert_locked(struct xe_ggtt_node *node, + u32 size, u32 align, u32 mm_flags) { return drm_mm_insert_node_generic(&node->ggtt->mm, &node->base, size, align, 0, mm_flags); @@ -687,9 +675,11 @@ int xe_ggtt_node_insert(struct xe_ggtt_node *node, u32 size, u32 align) * This function will allocate the struct %xe_ggtt_node and return its pointer. * This struct will then be freed after the node removal upon xe_ggtt_node_remove() * or xe_ggtt_node_remove_balloon_locked(). - * Having %xe_ggtt_node struct allocated doesn't mean that the node is already allocated - * in GGTT. Only the xe_ggtt_node_insert(), xe_ggtt_node_insert_locked(), - * xe_ggtt_node_insert_balloon_locked() will ensure the node is inserted or reserved in GGTT. + * + * Having %xe_ggtt_node struct allocated doesn't mean that the node is already + * allocated in GGTT. Only xe_ggtt_node_insert(), allocation through + * xe_ggtt_node_insert_transform(), or xe_ggtt_node_insert_balloon_locked() will ensure the node is inserted or reserved + * in GGTT. * * Return: A pointer to %xe_ggtt_node struct on success. An ERR_PTR otherwise. **/ @@ -752,13 +742,12 @@ size_t xe_ggtt_node_pt_size(const struct xe_ggtt_node *node) * @ggtt: the &xe_ggtt where node will be mapped * @node: the &xe_ggtt_node where this BO is mapped * @bo: the &xe_bo to be mapped - * @pat_index: Which pat_index to use. + * @pte: The pte flags to append. */ -void xe_ggtt_map_bo(struct xe_ggtt *ggtt, struct xe_ggtt_node *node, - struct xe_bo *bo, u16 pat_index) +static void xe_ggtt_map_bo(struct xe_ggtt *ggtt, struct xe_ggtt_node *node, + struct xe_bo *bo, u64 pte) { - - u64 start, pte, end; + u64 start, end; struct xe_res_cursor cur; if (XE_WARN_ON(!node)) @@ -767,7 +756,6 @@ void xe_ggtt_map_bo(struct xe_ggtt *ggtt, struct xe_ggtt_node *node, start = node->base.start; end = start + xe_bo_size(bo); - pte = ggtt->pt_ops->pte_encode_flags(bo, pat_index); if (!xe_bo_is_vram(bo) && !xe_bo_is_stolen(bo)) { xe_assert(xe_bo_device(bo), bo->ttm.ttm); @@ -797,10 +785,63 @@ void xe_ggtt_map_bo_unlocked(struct xe_ggtt *ggtt, struct xe_bo *bo) { u16 cache_mode = bo->flags & XE_BO_FLAG_NEEDS_UC ? XE_CACHE_NONE : XE_CACHE_WB; u16 pat_index = tile_to_xe(ggtt->tile)->pat.idx[cache_mode]; + u64 pte; mutex_lock(&ggtt->lock); - xe_ggtt_map_bo(ggtt, bo->ggtt_node[ggtt->tile->id], bo, pat_index); + pte = ggtt->pt_ops->pte_encode_flags(bo, pat_index); + xe_ggtt_map_bo(ggtt, bo->ggtt_node[ggtt->tile->id], bo, pte); + mutex_unlock(&ggtt->lock); +} + +/** + * xe_ggtt_node_insert_transform - Insert a newly allocated &xe_ggtt_node into the GGTT + * @ggtt: the &xe_ggtt where the node will inserted/reserved. + * @bo: The bo to be transformed + * @pte_flags: The extra GGTT flags to add to mapping. + * @size: size of the node + * @align: required alignment for node + * @transform: transformation function that will populate the GGTT node, or NULL for linear mapping. + * @arg: Extra argument to pass to the transformation function. + * + * This function allows inserting a GGTT node with a custom transformation function. + * This is useful for display to allow inserting rotated framebuffers to GGTT. + * + * Return: A pointer to %xe_ggtt_node struct on success. An ERR_PTR otherwise. + */ +struct xe_ggtt_node *xe_ggtt_node_insert_transform(struct xe_ggtt *ggtt, + struct xe_bo *bo, u64 pte_flags, + u64 size, u32 align, + xe_ggtt_transform_cb transform, void *arg) +{ + struct xe_ggtt_node *node; + int ret; + + node = xe_ggtt_node_init(ggtt); + if (IS_ERR(node)) + return ERR_CAST(node); + + if (mutex_lock_interruptible(&ggtt->lock) < 0) { + ret = -ERESTARTSYS; + goto err; + } + + ret = xe_ggtt_node_insert_locked(node, size, align, 0); + if (ret) + goto err_unlock; + + if (transform) + transform(ggtt, node, pte_flags, ggtt->pt_ops->ggtt_set_pte, arg); + else + xe_ggtt_map_bo(ggtt, node, bo, pte_flags); + mutex_unlock(&ggtt->lock); + return node; + +err_unlock: + mutex_unlock(&ggtt->lock); +err: + xe_ggtt_node_fini(node); + return ERR_PTR(ret); } static int __xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo, @@ -841,8 +882,9 @@ static int __xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo, } else { u16 cache_mode = bo->flags & XE_BO_FLAG_NEEDS_UC ? XE_CACHE_NONE : XE_CACHE_WB; u16 pat_index = tile_to_xe(ggtt->tile)->pat.idx[cache_mode]; + u64 pte = ggtt->pt_ops->pte_encode_flags(bo, pat_index); - xe_ggtt_map_bo(ggtt, bo->ggtt_node[tile_id], bo, pat_index); + xe_ggtt_map_bo(ggtt, bo->ggtt_node[tile_id], bo, pte); } mutex_unlock(&ggtt->lock); diff --git a/drivers/gpu/drm/xe/xe_ggtt.h b/drivers/gpu/drm/xe/xe_ggtt.h index df7196ec4696..9adfc58edf58 100644 --- a/drivers/gpu/drm/xe/xe_ggtt.h +++ b/drivers/gpu/drm/xe/xe_ggtt.h @@ -27,13 +27,14 @@ u64 xe_ggtt_start(struct xe_ggtt *ggtt); u64 xe_ggtt_size(struct xe_ggtt *ggtt); int xe_ggtt_node_insert(struct xe_ggtt_node *node, u32 size, u32 align); -int xe_ggtt_node_insert_locked(struct xe_ggtt_node *node, - u32 size, u32 align, u32 mm_flags); +struct xe_ggtt_node * +xe_ggtt_node_insert_transform(struct xe_ggtt *ggtt, + struct xe_bo *bo, u64 pte, + u64 size, u32 align, + xe_ggtt_transform_cb transform, void *arg); void xe_ggtt_node_remove(struct xe_ggtt_node *node, bool invalidate); bool xe_ggtt_node_allocated(const struct xe_ggtt_node *node); size_t xe_ggtt_node_pt_size(const struct xe_ggtt_node *node); -void xe_ggtt_map_bo(struct xe_ggtt *ggtt, struct xe_ggtt_node *node, - struct xe_bo *bo, u16 pat_index); void xe_ggtt_map_bo_unlocked(struct xe_ggtt *ggtt, struct xe_bo *bo); int xe_ggtt_insert_bo(struct xe_ggtt *ggtt, struct xe_bo *bo, struct drm_exec *exec); int xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo, diff --git a/drivers/gpu/drm/xe/xe_ggtt_types.h b/drivers/gpu/drm/xe/xe_ggtt_types.h index d773cf284c03..5fd723ce8108 100644 --- a/drivers/gpu/drm/xe/xe_ggtt_types.h +++ b/drivers/gpu/drm/xe/xe_ggtt_types.h @@ -71,6 +71,11 @@ struct xe_ggtt_node { bool invalidate_on_remove; }; +typedef void (*xe_ggtt_set_pte_fn)(struct xe_ggtt *ggtt, u64 addr, u64 pte); +typedef void (*xe_ggtt_transform_cb)(struct xe_ggtt *ggtt, + struct xe_ggtt_node *node, + u64 pte_flags, + xe_ggtt_set_pte_fn set_pte, void *arg); /** * struct xe_ggtt_pt_ops - GGTT Page table operations * Which can vary from platform to platform. @@ -78,8 +83,10 @@ struct xe_ggtt_node { struct xe_ggtt_pt_ops { /** @pte_encode_flags: Encode PTE flags for a given BO */ u64 (*pte_encode_flags)(struct xe_bo *bo, u16 pat_index); + /** @ggtt_set_pte: Directly write into GGTT's PTE */ - void (*ggtt_set_pte)(struct xe_ggtt *ggtt, u64 addr, u64 pte); + xe_ggtt_set_pte_fn ggtt_set_pte; + /** @ggtt_get_pte: Directly read from GGTT's PTE */ u64 (*ggtt_get_pte)(struct xe_ggtt *ggtt, u64 addr); }; -- cgit v1.2.3 From c818b2651573b2ab3e5dc71dcbfe89b5e0fe9c13 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 8 Jan 2026 11:10:18 +0100 Subject: drm/xe: Add xe_ggtt_node_addr() to avoid dereferencing xe_ggtt_node This function makes it possible to add an offset that is applied to all xe_ggtt_node's, and hides the internals from all its users. Signed-off-by: Maarten Lankhorst Reviewed-by: Matthew Brost Link: https://patch.msgid.link/20260108101014.579906-12-dev@lankhorst.se --- drivers/gpu/drm/xe/xe_bo.h | 8 +++++--- drivers/gpu/drm/xe/xe_ggtt.c | 11 +++++++++++ drivers/gpu/drm/xe/xe_ggtt.h | 2 ++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_bo.h b/drivers/gpu/drm/xe/xe_bo.h index 8ab4474129c3..c914ab719f20 100644 --- a/drivers/gpu/drm/xe/xe_bo.h +++ b/drivers/gpu/drm/xe/xe_bo.h @@ -9,6 +9,7 @@ #include #include "xe_bo_types.h" +#include "xe_ggtt.h" #include "xe_macros.h" #include "xe_validation.h" #include "xe_vm_types.h" @@ -252,13 +253,14 @@ static inline u32 __xe_bo_ggtt_addr(struct xe_bo *bo, u8 tile_id) { struct xe_ggtt_node *ggtt_node = bo->ggtt_node[tile_id]; + u64 offset; if (XE_WARN_ON(!ggtt_node)) return 0; - XE_WARN_ON(ggtt_node->base.size > xe_bo_size(bo)); - XE_WARN_ON(ggtt_node->base.start + ggtt_node->base.size > (1ull << 32)); - return ggtt_node->base.start; + offset = xe_ggtt_node_addr(ggtt_node); + XE_WARN_ON(offset + xe_bo_size(bo) > (1ull << 32)); + return offset; } static inline u32 diff --git a/drivers/gpu/drm/xe/xe_ggtt.c b/drivers/gpu/drm/xe/xe_ggtt.c index 2bd386b0f7b9..37c1ccca23bf 100644 --- a/drivers/gpu/drm/xe/xe_ggtt.c +++ b/drivers/gpu/drm/xe/xe_ggtt.c @@ -1185,3 +1185,14 @@ u64 xe_ggtt_read_pte(struct xe_ggtt *ggtt, u64 offset) { return ioread64(ggtt->gsm + (offset / XE_PAGE_SIZE)); } + +/** + * xe_ggtt_node_addr - Get @node offset in GGTT. + * @node: &xe_ggtt_node + * + * Get the GGTT offset for allocated node. + */ +u64 xe_ggtt_node_addr(const struct xe_ggtt_node *node) +{ + return node->base.start; +} diff --git a/drivers/gpu/drm/xe/xe_ggtt.h b/drivers/gpu/drm/xe/xe_ggtt.h index 9adfc58edf58..76336a6296c4 100644 --- a/drivers/gpu/drm/xe/xe_ggtt.h +++ b/drivers/gpu/drm/xe/xe_ggtt.h @@ -61,4 +61,6 @@ void xe_ggtt_might_lock(struct xe_ggtt *ggtt); u64 xe_ggtt_encode_pte_flags(struct xe_ggtt *ggtt, struct xe_bo *bo, u16 pat_index); u64 xe_ggtt_read_pte(struct xe_ggtt *ggtt, u64 offset); +u64 xe_ggtt_node_addr(const struct xe_ggtt_node *node); + #endif -- cgit v1.2.3 From a7ae0836917ca617434c416f9c61dc6024d04949 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 8 Jan 2026 11:10:19 +0100 Subject: drm/xe/display: Avoid dereferencing xe_ggtt_node Start using xe_ggtt_node_addr, and avoid comparing the base offset as vma->node is dynamically allocated. Also sneak in a xe_bo_size() for stolen, too small to put as separate commit. Reviewed-by: Matthew Brost Signed-off-by: Maarten Lankhorst Acked-by: Rodrigo Vivi Link: https://patch.msgid.link/20260108101014.579906-13-dev@lankhorst.se --- drivers/gpu/drm/xe/compat-i915-headers/i915_vma.h | 4 ++-- drivers/gpu/drm/xe/display/xe_fb_pin.c | 4 ++-- drivers/gpu/drm/xe/display/xe_stolen.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/xe/compat-i915-headers/i915_vma.h b/drivers/gpu/drm/xe/compat-i915-headers/i915_vma.h index b17e3bab23d5..c4b5adaaa99a 100644 --- a/drivers/gpu/drm/xe/compat-i915-headers/i915_vma.h +++ b/drivers/gpu/drm/xe/compat-i915-headers/i915_vma.h @@ -8,7 +8,7 @@ #include -#include "xe_ggtt_types.h" +#include "xe_ggtt.h" #include @@ -30,7 +30,7 @@ struct i915_vma { static inline u32 i915_ggtt_offset(const struct i915_vma *vma) { - return vma->node->base.start; + return xe_ggtt_node_addr(vma->node); } #endif diff --git a/drivers/gpu/drm/xe/display/xe_fb_pin.c b/drivers/gpu/drm/xe/display/xe_fb_pin.c index c7c9c2e9c233..77b05b556ba6 100644 --- a/drivers/gpu/drm/xe/display/xe_fb_pin.c +++ b/drivers/gpu/drm/xe/display/xe_fb_pin.c @@ -206,7 +206,7 @@ static void write_ggtt_rotated_node(struct xe_ggtt *ggtt, struct xe_ggtt_node *n struct fb_rotate_args *args = data; struct xe_bo *bo = args->bo; const struct intel_rotation_info *rot_info = &args->view->rotated; - u32 ggtt_ofs = node->base.start; + u32 ggtt_ofs = xe_ggtt_node_addr(node); for (u32 i = 0; i < ARRAY_SIZE(rot_info->plane); i++) write_ggtt_rotated(ggtt, &ggtt_ofs, pte_flags, write_pte, @@ -353,7 +353,7 @@ static void __xe_unpin_fb_vma(struct i915_vma *vma) if (vma->dpt) xe_bo_unpin_map_no_vm(vma->dpt); else if (!xe_ggtt_node_allocated(vma->bo->ggtt_node[tile_id]) || - vma->bo->ggtt_node[tile_id]->base.start != vma->node->base.start) + vma->bo->ggtt_node[tile_id] != vma->node) xe_ggtt_node_remove(vma->node, false); ttm_bo_reserve(&vma->bo->ttm, false, false, NULL); diff --git a/drivers/gpu/drm/xe/display/xe_stolen.c b/drivers/gpu/drm/xe/display/xe_stolen.c index 12771709183a..8dc2f86ec602 100644 --- a/drivers/gpu/drm/xe/display/xe_stolen.c +++ b/drivers/gpu/drm/xe/display/xe_stolen.c @@ -78,7 +78,7 @@ static u64 xe_stolen_node_address(const struct intel_stolen_node *node) static u64 xe_stolen_node_size(const struct intel_stolen_node *node) { - return node->bo->ttm.base.size; + return xe_bo_size(node->bo); } static struct intel_stolen_node *xe_stolen_node_alloc(struct drm_device *drm) -- cgit v1.2.3 From 9086170bfb925c90e298134791a9851ed626b873 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 8 Jan 2026 11:10:20 +0100 Subject: drm/xe: Do not dereference ggtt_node in xe_bo.c A careful inspection of __xe_ggtt_insert_bo_at() shows that the ggtt_node can always be seen as inserted from xe_bo.c due to the way error handling is performed. The checks are also a little bit too paranoid, since we never create a bo with ggtt_node[id] initialised but not inserted into the GGTT, which can be seen by looking at __xe_ggtt_insert_bo_at() Additionally, the size of the GGTT is never bigger than 4 GB, so adding a check at that level is incorrect. Signed-off-by: Maarten Lankhorst Reviewed-by: Matthew Brost Link: https://patch.msgid.link/20260108101014.579906-14-dev@lankhorst.se --- drivers/gpu/drm/xe/xe_bo.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index 408c74216fdf..917e50c276ac 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -1715,7 +1715,7 @@ static void xe_ttm_bo_destroy(struct ttm_buffer_object *ttm_bo) xe_assert(xe, list_empty(&ttm_bo->base.gpuva.list)); for_each_tile(tile, xe, id) - if (bo->ggtt_node[id] && bo->ggtt_node[id]->base.size) + if (bo->ggtt_node[id]) xe_ggtt_remove_bo(tile->mem.ggtt, bo); #ifdef CONFIG_PROC_FS @@ -3609,8 +3609,8 @@ void xe_bo_put(struct xe_bo *bo) might_lock(&bo->client->bos_lock); #endif for_each_tile(tile, xe_bo_device(bo), id) - if (bo->ggtt_node[id] && bo->ggtt_node[id]->ggtt) - xe_ggtt_might_lock(bo->ggtt_node[id]->ggtt); + if (bo->ggtt_node[id]) + xe_ggtt_might_lock(tile->mem.ggtt); drm_gem_object_put(&bo->ttm.base); } } -- cgit v1.2.3 From 8d88aa149a297a179d8381ccf6170e48d666dc63 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 8 Jan 2026 11:10:21 +0100 Subject: drm/xe: Improve xe_gt_sriov_pf_config GGTT handling Do not directly dereference xe_ggtt_node, and add a function to retrieve the allocated GGTT size. Reviewed-by: Matthew.brost@intel.com Reviewed-by: Michal Wajdeczko Signed-off-by: Maarten Lankhorst Link: https://patch.msgid.link/20260108101014.579906-15-dev@lankhorst.se --- drivers/gpu/drm/xe/xe_ggtt.c | 11 +++++++++++ drivers/gpu/drm/xe/xe_ggtt.h | 1 + drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c | 15 ++++++++------- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_ggtt.c b/drivers/gpu/drm/xe/xe_ggtt.c index 37c1ccca23bf..1d748d1aeb3c 100644 --- a/drivers/gpu/drm/xe/xe_ggtt.c +++ b/drivers/gpu/drm/xe/xe_ggtt.c @@ -1196,3 +1196,14 @@ u64 xe_ggtt_node_addr(const struct xe_ggtt_node *node) { return node->base.start; } + +/** + * xe_ggtt_node_size - Get @node allocation size. + * @node: &xe_ggtt_node + * + * Get the allocated node's size. + */ +u64 xe_ggtt_node_size(const struct xe_ggtt_node *node) +{ + return node->base.size; +} diff --git a/drivers/gpu/drm/xe/xe_ggtt.h b/drivers/gpu/drm/xe/xe_ggtt.h index 76336a6296c4..70d5e07ac4b6 100644 --- a/drivers/gpu/drm/xe/xe_ggtt.h +++ b/drivers/gpu/drm/xe/xe_ggtt.h @@ -62,5 +62,6 @@ u64 xe_ggtt_encode_pte_flags(struct xe_ggtt *ggtt, struct xe_bo *bo, u16 pat_ind u64 xe_ggtt_read_pte(struct xe_ggtt *ggtt, u64 offset); u64 xe_ggtt_node_addr(const struct xe_ggtt_node *node); +u64 xe_ggtt_node_size(const struct xe_ggtt_node *node); #endif diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c index bed6580d8d09..9f2525f3cb37 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c @@ -284,7 +284,7 @@ static u32 encode_config_ggtt(u32 *cfg, const struct xe_gt_sriov_config *config, if (!xe_ggtt_node_allocated(node)) return 0; - return encode_ggtt(cfg, node->base.start, node->base.size, details); + return encode_ggtt(cfg, xe_ggtt_node_addr(node), xe_ggtt_node_size(node), details); } static u32 encode_config_sched(struct xe_gt *gt, u32 *cfg, u32 n, @@ -545,9 +545,9 @@ static int pf_provision_vf_ggtt(struct xe_gt *gt, unsigned int vfid, u64 size) xe_ggtt_assign(node, vfid); xe_gt_sriov_dbg_verbose(gt, "VF%u assigned GGTT %llx-%llx\n", - vfid, node->base.start, node->base.start + node->base.size - 1); + vfid, xe_ggtt_node_addr(node), xe_ggtt_node_addr(node) + size - 1); - err = pf_distribute_config_ggtt(gt->tile, vfid, node->base.start, node->base.size); + err = pf_distribute_config_ggtt(gt->tile, vfid, xe_ggtt_node_addr(node), size); if (unlikely(err)) goto err; @@ -564,7 +564,7 @@ static u64 pf_get_vf_config_ggtt(struct xe_gt *gt, unsigned int vfid) struct xe_ggtt_node *node = config->ggtt_region; xe_gt_assert(gt, xe_gt_is_main_type(gt)); - return xe_ggtt_node_allocated(node) ? node->base.size : 0; + return xe_ggtt_node_allocated(node) ? xe_ggtt_node_size(node) : 0; } /** @@ -3040,11 +3040,12 @@ int xe_gt_sriov_pf_config_print_ggtt(struct xe_gt *gt, struct drm_printer *p) if (!xe_ggtt_node_allocated(config->ggtt_region)) continue; - string_get_size(config->ggtt_region->base.size, 1, STRING_UNITS_2, + string_get_size(xe_ggtt_node_size(config->ggtt_region), 1, STRING_UNITS_2, buf, sizeof(buf)); drm_printf(p, "VF%u:\t%#0llx-%#llx\t(%s)\n", - n, config->ggtt_region->base.start, - config->ggtt_region->base.start + config->ggtt_region->base.size - 1, + n, xe_ggtt_node_addr(config->ggtt_region), + xe_ggtt_node_addr(config->ggtt_region) + + xe_ggtt_node_size(config->ggtt_region) - 1, buf); } -- cgit v1.2.3 From 987167b1199c428765b0f76b9b6587dd4ccde3e6 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 8 Jan 2026 11:10:22 +0100 Subject: drm/xe: Privatize xe_ggtt_node Nothing requires it any more, make the member private. Reviewed-by: Matthew Brost Signed-off-by: Maarten Lankhorst Link: https://patch.msgid.link/20260108101014.579906-16-dev@lankhorst.se --- drivers/gpu/drm/xe/xe_ggtt.c | 18 ++++++++++++++++++ drivers/gpu/drm/xe/xe_ggtt_types.h | 19 +------------------ 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_ggtt.c b/drivers/gpu/drm/xe/xe_ggtt.c index 1d748d1aeb3c..cb23d97845a8 100644 --- a/drivers/gpu/drm/xe/xe_ggtt.c +++ b/drivers/gpu/drm/xe/xe_ggtt.c @@ -67,6 +67,24 @@ * give us the correct placement for free. */ +/** + * struct xe_ggtt_node - A node in GGTT. + * + * This struct needs to be initialized (only-once) with xe_ggtt_node_init() before any node + * insertion, reservation, or 'ballooning'. + * It will, then, be finalized by either xe_ggtt_node_remove() or xe_ggtt_node_deballoon(). + */ +struct xe_ggtt_node { + /** @ggtt: Back pointer to xe_ggtt where this region will be inserted at */ + struct xe_ggtt *ggtt; + /** @base: A drm_mm_node */ + struct drm_mm_node base; + /** @delayed_removal_work: The work struct for the delayed removal */ + struct work_struct delayed_removal_work; + /** @invalidate_on_remove: If it needs invalidation upon removal */ + bool invalidate_on_remove; +}; + static u64 xelp_ggtt_pte_flags(struct xe_bo *bo, u16 pat_index) { u64 pte = XE_PAGE_PRESENT; diff --git a/drivers/gpu/drm/xe/xe_ggtt_types.h b/drivers/gpu/drm/xe/xe_ggtt_types.h index 5fd723ce8108..d82b71a198bc 100644 --- a/drivers/gpu/drm/xe/xe_ggtt_types.h +++ b/drivers/gpu/drm/xe/xe_ggtt_types.h @@ -11,6 +11,7 @@ #include "xe_pt_types.h" struct xe_bo; +struct xe_ggtt_node; struct xe_gt; /** @@ -53,24 +54,6 @@ struct xe_ggtt { struct workqueue_struct *wq; }; -/** - * struct xe_ggtt_node - A node in GGTT. - * - * This struct needs to be initialized (only-once) with xe_ggtt_node_init() before any node - * insertion, reservation, or 'ballooning'. - * It will, then, be finalized by either xe_ggtt_node_remove() or xe_ggtt_node_deballoon(). - */ -struct xe_ggtt_node { - /** @ggtt: Back pointer to xe_ggtt where this region will be inserted at */ - struct xe_ggtt *ggtt; - /** @base: A drm_mm_node */ - struct drm_mm_node base; - /** @delayed_removal_work: The work struct for the delayed removal */ - struct work_struct delayed_removal_work; - /** @invalidate_on_remove: If it needs invalidation upon removal */ - bool invalidate_on_remove; -}; - typedef void (*xe_ggtt_set_pte_fn)(struct xe_ggtt *ggtt, u64 addr, u64 pte); typedef void (*xe_ggtt_transform_cb)(struct xe_ggtt *ggtt, struct xe_ggtt_node *node, -- cgit v1.2.3 From d758c8d6e2624d7be12a6c070a3387d6703e4a7c Mon Sep 17 00:00:00 2001 From: Balasubramani Vivekanandan Date: Fri, 19 Dec 2025 20:20:25 +0530 Subject: drm/xe/device: Convert wait for lmem init into an assert Prior to lmem init check, driver is waiting for the pcode uncore_init status. uncore_init status will be flagged after the complete boot and initialization of the SoC by the pcode. uncore_init confirms that lmem init and mmio unblock has been already completed. It makes no sense to check for lmem init after the pcode uncore_init check. So change the wait for lmem init check into an assert which confirms lmem init is set. Signed-off-by: Balasubramani Vivekanandan Reviewed-by: Matt Roper Link: https://patch.msgid.link/20251219145024.2955946-2-balasubramani.vivekanandan@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/xe_device.c | 73 +++++++++--------------------------------- 1 file changed, 16 insertions(+), 57 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index e400ad5c9f9e..7190b208e3da 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include @@ -654,62 +653,14 @@ mask_err: return err; } -static int lmem_initializing(struct xe_device *xe) +static void assert_lmem_ready(struct xe_device *xe) { - if (xe_mmio_read32(xe_root_tile_mmio(xe), GU_CNTL) & LMEM_INIT) - return 0; - - if (signal_pending(current)) - return -EINTR; - - return 1; -} - -static int wait_for_lmem_ready(struct xe_device *xe) -{ - const unsigned long TIMEOUT_SEC = 60; - unsigned long prev_jiffies; - int initializing; - - if (!IS_DGFX(xe)) - return 0; - - if (IS_SRIOV_VF(xe)) - return 0; - - if (!lmem_initializing(xe)) - return 0; - - drm_dbg(&xe->drm, "Waiting for lmem initialization\n"); - prev_jiffies = jiffies; - - /* - * The boot firmware initializes local memory and - * assesses its health. If memory training fails, - * the punit will have been instructed to keep the GT powered - * down.we won't be able to communicate with it - * - * If the status check is done before punit updates the register, - * it can lead to the system being unusable. - * use a timeout and defer the probe to prevent this. - */ - poll_timeout_us(initializing = lmem_initializing(xe), - initializing <= 0, - 20 * USEC_PER_MSEC, TIMEOUT_SEC * USEC_PER_SEC, true); - if (initializing < 0) - return initializing; - - if (initializing) { - drm_dbg(&xe->drm, "lmem not initialized by firmware\n"); - return -EPROBE_DEFER; - } - - drm_dbg(&xe->drm, "lmem ready after %ums", - jiffies_to_msecs(jiffies - prev_jiffies)); + if (!IS_DGFX(xe) || IS_SRIOV_VF(xe)) + return; - return 0; + xe_assert(xe, xe_mmio_read32(xe_root_tile_mmio(xe), GU_CNTL) & + LMEM_INIT); } -ALLOW_ERROR_INJECTION(wait_for_lmem_ready, ERRNO); /* See xe_pci_probe() */ static void vf_update_device_info(struct xe_device *xe) { @@ -764,6 +715,11 @@ int xe_device_probe_early(struct xe_device *xe) if (IS_SRIOV_VF(xe)) vf_update_device_info(xe); + /* + * Check for pcode uncore_init status to confirm if the SoC + * initialization is complete. Until done, any MMIO or lmem access from + * the driver will be blocked + */ err = xe_pcode_probe_early(xe); if (err || xe_survivability_mode_is_requested(xe)) { int save_err = err; @@ -780,9 +736,12 @@ int xe_device_probe_early(struct xe_device *xe) return save_err; } - err = wait_for_lmem_ready(xe); - if (err) - return err; + /* + * Make sure the lmem is initialized and ready to use. xe_pcode_ready() + * is flagged after full initialization is complete. Assert if lmem is + * not initialized. + */ + assert_lmem_ready(xe); xe->wedged.mode = xe_device_validate_wedged_mode(xe, xe_modparam.wedged_mode) ? XE_WEDGED_MODE_DEFAULT : xe_modparam.wedged_mode; -- cgit v1.2.3 From 65b65ffcf669c37e120bcfd3d9cef62ac961bc60 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Wed, 7 Jan 2026 17:13:42 -0800 Subject: drm/xe/gsc: Make GSC FW load optional for newer platforms On newer platforms GSC FW is only required for content protection features, so the core driver features work perfectly fine without it (and we did in fact not enable it to start with on PTL). Therefore, we can selectively enable the GSC only if the FW is found on disk, without failing if it is not found. Note that this means that the FW can now be enabled (i.e., we're looking for it) but not available (i.e., we haven't found it), so checks on FW support should use the latter state to decide whether to go on or not. As part of the rework, the message for FW not found has been cleaned up to be more readable. While at it, drop the comment about xe_uc_fw_init() since the code has been reworked and the statement no longer applies. Signed-off-by: Daniele Ceraolo Spurio Cc: Rodrigo Vivi Cc: Julia Filipchuk Reviewed-by: Rodrigo Vivi Reviewed-by: Julia Filipchuk Link: https://patch.msgid.link/20260108011340.2562349-6-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/xe/display/xe_hdcp_gsc.c | 2 +- drivers/gpu/drm/xe/xe_gsc.c | 13 +++++++------ drivers/gpu/drm/xe/xe_uc_fw.c | 10 +++++++--- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c b/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c index 07acae121aa7..ed1f65f5ef4d 100644 --- a/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c +++ b/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c @@ -39,7 +39,7 @@ static bool intel_hdcp_gsc_check_status(struct drm_device *drm) struct xe_gt *gt = tile->media_gt; struct xe_gsc *gsc = >->uc.gsc; - if (!gsc || !xe_uc_fw_is_enabled(&gsc->fw)) { + if (!gsc || !xe_uc_fw_is_available(&gsc->fw)) { drm_dbg_kms(&xe->drm, "GSC Components not ready for HDCP2.x\n"); return false; diff --git a/drivers/gpu/drm/xe/xe_gsc.c b/drivers/gpu/drm/xe/xe_gsc.c index a3157b0fe791..e5c234f3d795 100644 --- a/drivers/gpu/drm/xe/xe_gsc.c +++ b/drivers/gpu/drm/xe/xe_gsc.c @@ -414,15 +414,16 @@ int xe_gsc_init(struct xe_gsc *gsc) } /* - * Some platforms can have GuC but not GSC. That would cause - * xe_uc_fw_init(gsc) to return a "not supported" failure code and abort - * all firmware loading. So check for GSC being enabled before - * propagating the failure back up. That way the higher level will keep - * going and load GuC as appropriate. + * Starting from BMG the GSC is no longer needed for MC6 entry, so the + * only missing features if the FW is lacking would be the content + * protection ones. This is acceptable, so we allow the driver load to + * continue if the GSC FW is missing. */ ret = xe_uc_fw_init(&gsc->fw); if (!xe_uc_fw_is_enabled(&gsc->fw)) return 0; + else if (gt_to_xe(gt)->info.platform >= XE_BATTLEMAGE && !xe_uc_fw_is_available(&gsc->fw)) + return 0; else if (ret) goto out; @@ -614,7 +615,7 @@ void xe_gsc_print_info(struct xe_gsc *gsc, struct drm_printer *p) drm_printf(p, "\tfound security version %u\n", gsc->security_version); - if (!xe_uc_fw_is_enabled(&gsc->fw)) + if (!xe_uc_fw_is_available(&gsc->fw)) return; CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GSC); diff --git a/drivers/gpu/drm/xe/xe_uc_fw.c b/drivers/gpu/drm/xe/xe_uc_fw.c index 85544c214274..5d10a6c34604 100644 --- a/drivers/gpu/drm/xe/xe_uc_fw.c +++ b/drivers/gpu/drm/xe/xe_uc_fw.c @@ -739,7 +739,7 @@ static int uc_fw_request(struct xe_uc_fw *uc_fw, const struct firmware **firmwar return 0; } - err = request_firmware(&fw, uc_fw->path, dev); + err = firmware_request_nowarn(&fw, uc_fw->path, dev); if (err) goto fail; @@ -768,8 +768,12 @@ fail: XE_UC_FIRMWARE_MISSING : XE_UC_FIRMWARE_ERROR); - xe_gt_notice(gt, "%s firmware %s: fetch failed with error %pe\n", - xe_uc_fw_type_repr(uc_fw->type), uc_fw->path, ERR_PTR(err)); + if (err == -ENOENT) + xe_gt_info(gt, "%s firmware %s not found\n", + xe_uc_fw_type_repr(uc_fw->type), uc_fw->path); + else + xe_gt_notice(gt, "%s firmware %s: fetch failed with error %pe\n", + xe_uc_fw_type_repr(uc_fw->type), uc_fw->path, ERR_PTR(err)); xe_gt_info(gt, "%s firmware(s) can be downloaded from %s\n", xe_uc_fw_type_repr(uc_fw->type), XE_UC_FIRMWARE_URL); -- cgit v1.2.3 From 6d24027d555e46e9f302523c95b3816198779f4d Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Wed, 7 Jan 2026 17:13:43 -0800 Subject: drm/xe/ptl: Define GSC for PTL PTL is identified by GSC major version 105. The compatibility version is still 1.0. Signed-off-by: Daniele Ceraolo Spurio Cc: Rodrigo Vivi Cc: Julia Filipchuk Reviewed-by: Julia Filipchuk Link: https://patch.msgid.link/20260108011340.2562349-7-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/xe/xe_uc_fw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/xe/xe_uc_fw.c b/drivers/gpu/drm/xe/xe_uc_fw.c index 5d10a6c34604..f5788db5073c 100644 --- a/drivers/gpu/drm/xe/xe_uc_fw.c +++ b/drivers/gpu/drm/xe/xe_uc_fw.c @@ -141,6 +141,7 @@ struct fw_blobs_by_type { /* for the GSC FW we match the compatibility version and not the release one */ #define XE_GSC_FIRMWARE_DEFS(fw_def, major_ver) \ + fw_def(PANTHERLAKE, GT_TYPE_ANY, major_ver(xe, gsc, ptl, 105, 1, 0)) \ fw_def(LUNARLAKE, GT_TYPE_ANY, major_ver(xe, gsc, lnl, 104, 1, 0)) \ fw_def(METEORLAKE, GT_TYPE_ANY, major_ver(i915, gsc, mtl, 102, 1, 0)) -- cgit v1.2.3 From b1dcec9bd8a1de5fe04ecb3831f8db0a5c059970 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Wed, 7 Jan 2026 17:13:44 -0800 Subject: drm/xe/ptl: Enable PXP for PTL Now that the GSC FW is defined, we can enable PXP for PTL. The feature will only be turned on if the binary is found on disk. Signed-off-by: Daniele Ceraolo Spurio Cc: Rodrigo Vivi Cc: Julia Filipchuk Reviewed-by: Rodrigo Vivi Link: https://patch.msgid.link/20260108011340.2562349-8-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/xe/xe_pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index a1fdca451ce0..673db1e82ec3 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -392,6 +392,7 @@ static const struct xe_device_desc ptl_desc = { .has_sriov = true, .has_mem_copy_instr = true, .has_pre_prod_wa = 1, + .has_pxp = true, .max_gt_per_tile = 2, .needs_scratch = true, .needs_shared_vf_gt_wq = true, -- cgit v1.2.3 From c332fba805d659eca1f8e3a41d259c03421e81f1 Mon Sep 17 00:00:00 2001 From: Karthik Poosa Date: Tue, 13 Jan 2026 02:05:18 +0530 Subject: drm/xe/hwmon: Expose temperature limits Read temperature limits using pcode mailbox and expose shutdown temperature limit as tempX_emergency, critical temperature limit as tempX_crit and GPU max temperature limit as temp2_max. Update Xe hwmon documentation with above entries. v2: - Resolve a documentation warning. - Address below review comments from Raag. - Update date and kernel version in Xe hwmon documentation. - Remove explicit disable of has_mbx_thermal_info for unsupported platforms. - Remove unnecessary default case in switches. - Remove obvious comments. - Use TEMP_LIMIT_MAX to compute number of dwords needed in xe_hwmon_thermal_info. - Remove THERMAL_LIMITS_DWORDS macro. - Use has_mbx_thermal_info for checking thermal mailbox support. v3: - Address below minor comments. (Raag) - Group new temperature attributes with existing temperature attributes as per channel index in Xe hwmon documentation. - Rename enums of xe_temp_limit to improve clarity. - Use DIV_ROUND_UP to calculate dwords needed for temperature limits. - Use return instead of breaks in xe_hwmon_temp_read. - Minor aesthetic refinements. v4: - Remove a redundant break. (Raag) - Update drm_dbg to drm_warn to inform user of unavailability for thermal mailbox on expected platforms. Signed-off-by: Karthik Poosa Reviewed-by: Raag Jadav Link: https://patch.msgid.link/20260112203521.1014388-2-karthik.poosa@intel.com Signed-off-by: Rodrigo Vivi --- .../ABI/testing/sysfs-driver-intel-xe-hwmon | 40 ++++++++ drivers/gpu/drm/xe/xe_device_types.h | 2 + drivers/gpu/drm/xe/xe_hwmon.c | 102 ++++++++++++++++++++- drivers/gpu/drm/xe/xe_pci.c | 3 + drivers/gpu/drm/xe/xe_pci_types.h | 1 + drivers/gpu/drm/xe/xe_pcode_api.h | 3 + 6 files changed, 148 insertions(+), 3 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon index d9e2b17c6872..2b00ef13b6ad 100644 --- a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon +++ b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon @@ -109,6 +109,22 @@ Description: RO. Package current voltage in millivolt. Only supported for particular Intel Xe graphics platforms. +What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon/temp2_crit +Date: January 2026 +KernelVersion: 7.0 +Contact: intel-xe@lists.freedesktop.org +Description: RO. Package critical temperature in millidegree Celsius. + + Only supported for particular Intel Xe graphics platforms. + +What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon/temp2_emergency +Date: January 2026 +KernelVersion: 7.0 +Contact: intel-xe@lists.freedesktop.org +Description: RO. Package shutdown temperature in millidegree Celsius. + + Only supported for particular Intel Xe graphics platforms. + What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon/temp2_input Date: March 2025 KernelVersion: 6.15 @@ -117,6 +133,30 @@ Description: RO. Package temperature in millidegree Celsius. Only supported for particular Intel Xe graphics platforms. +What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon/temp2_max +Date: January 2026 +KernelVersion: 7.0 +Contact: intel-xe@lists.freedesktop.org +Description: RO. Package maximum temperature limit in millidegree Celsius. + + Only supported for particular Intel Xe graphics platforms. + +What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon/temp3_crit +Date: January 2026 +KernelVersion: 7.0 +Contact: intel-xe@lists.freedesktop.org +Description: RO. VRAM critical temperature in millidegree Celsius. + + Only supported for particular Intel Xe graphics platforms. + +What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon/temp3_emergency +Date: January 2026 +KernelVersion: 7.0 +Contact: intel-xe@lists.freedesktop.org +Description: RO. VRAM shutdown temperature in millidegree Celsius. + + Only supported for particular Intel Xe graphics platforms. + What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon/temp3_input Date: March 2025 KernelVersion: 6.15 diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index 4dab3057f58d..f689766adcb1 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -341,6 +341,8 @@ struct xe_device { * pcode mailbox commands. */ u8 has_mbx_power_limits:1; + /** @info.has_mbx_thermal_info: Device supports thermal mailbox commands */ + u8 has_mbx_thermal_info:1; /** @info.has_mem_copy_instr: Device supports MEM_COPY instruction */ u8 has_mem_copy_instr:1; /** @info.has_mert: Device has standalone MERT */ diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c index ff2aea52ef75..7eb6a76fa217 100644 --- a/drivers/gpu/drm/xe/xe_hwmon.c +++ b/drivers/gpu/drm/xe/xe_hwmon.c @@ -53,6 +53,15 @@ enum xe_fan_channel { FAN_MAX, }; +enum xe_temp_limit { + TEMP_LIMIT_PKG_SHUTDOWN, + TEMP_LIMIT_PKG_CRIT, + TEMP_LIMIT_MEM_SHUTDOWN, + TEMP_LIMIT_PKG_MAX, + TEMP_LIMIT_MEM_CRIT, + TEMP_LIMIT_MAX +}; + /* Attribute index for powerX_xxx_interval sysfs entries */ enum sensor_attr_power { SENSOR_INDEX_PSYS_PL1, @@ -111,6 +120,18 @@ struct xe_hwmon_fan_info { u64 time_prev; }; +/** + * struct xe_hwmon_thermal_info - to store temperature data + */ +struct xe_hwmon_thermal_info { + union { + /** @limit: temperatures limits */ + u8 limit[TEMP_LIMIT_MAX]; + /** @data: temperature limits in dwords */ + u32 data[DIV_ROUND_UP(TEMP_LIMIT_MAX, sizeof(u32))]; + }; +}; + /** * struct xe_hwmon - xe hwmon data structure */ @@ -137,7 +158,8 @@ struct xe_hwmon { u32 pl1_on_boot[CHANNEL_MAX]; /** @pl2_on_boot: power limit PL2 on boot */ u32 pl2_on_boot[CHANNEL_MAX]; - + /** @temp: Temperature info */ + struct xe_hwmon_thermal_info temp; }; static int xe_hwmon_pcode_read_power_limit(const struct xe_hwmon *hwmon, u32 attr, int channel, @@ -677,8 +699,11 @@ static const struct attribute_group *hwmon_groups[] = { }; static const struct hwmon_channel_info * const hwmon_info[] = { - HWMON_CHANNEL_INFO(temp, HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL, - HWMON_T_INPUT | HWMON_T_LABEL), + HWMON_CHANNEL_INFO(temp, + HWMON_T_LABEL, + HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL | + HWMON_T_MAX, + HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL), HWMON_CHANNEL_INFO(power, HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_LABEL | HWMON_P_CRIT | HWMON_P_CAP, HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_LABEL | HWMON_P_CAP), @@ -689,6 +714,19 @@ static const struct hwmon_channel_info * const hwmon_info[] = { NULL }; +static int xe_hwmon_pcode_read_thermal_info(struct xe_hwmon *hwmon) +{ + struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe); + int ret; + + ret = xe_pcode_read(root_tile, PCODE_MBOX(PCODE_THERMAL_INFO, READ_THERMAL_LIMITS, 0), + &hwmon->temp.data[0], &hwmon->temp.data[1]); + drm_dbg(&hwmon->xe->drm, "thermal info read val 0x%x val1 0x%x\n", + hwmon->temp.data[0], hwmon->temp.data[1]); + + return ret; +} + /* I1 is exposed as power_crit or as curr_crit depending on bit 31 */ static int xe_hwmon_pcode_read_i1(const struct xe_hwmon *hwmon, u32 *uval) { @@ -787,6 +825,31 @@ static umode_t xe_hwmon_temp_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel) { switch (attr) { + case hwmon_temp_emergency: + switch (channel) { + case CHANNEL_PKG: + return hwmon->temp.limit[TEMP_LIMIT_PKG_SHUTDOWN] ? 0444 : 0; + case CHANNEL_VRAM: + return hwmon->temp.limit[TEMP_LIMIT_MEM_SHUTDOWN] ? 0444 : 0; + default: + return 0; + } + case hwmon_temp_crit: + switch (channel) { + case CHANNEL_PKG: + return hwmon->temp.limit[TEMP_LIMIT_PKG_CRIT] ? 0444 : 0; + case CHANNEL_VRAM: + return hwmon->temp.limit[TEMP_LIMIT_MEM_CRIT] ? 0444 : 0; + default: + return 0; + } + case hwmon_temp_max: + switch (channel) { + case CHANNEL_PKG: + return hwmon->temp.limit[TEMP_LIMIT_PKG_MAX] ? 0444 : 0; + default: + return 0; + } case hwmon_temp_input: case hwmon_temp_label: return xe_reg_is_valid(xe_hwmon_get_reg(hwmon, REG_TEMP, channel)) ? 0444 : 0; @@ -808,6 +871,36 @@ xe_hwmon_temp_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val) /* HW register value is in degrees Celsius, convert to millidegrees. */ *val = REG_FIELD_GET(TEMP_MASK, reg_val) * MILLIDEGREE_PER_DEGREE; return 0; + case hwmon_temp_emergency: + switch (channel) { + case CHANNEL_PKG: + *val = hwmon->temp.limit[TEMP_LIMIT_PKG_SHUTDOWN] * MILLIDEGREE_PER_DEGREE; + return 0; + case CHANNEL_VRAM: + *val = hwmon->temp.limit[TEMP_LIMIT_MEM_SHUTDOWN] * MILLIDEGREE_PER_DEGREE; + return 0; + default: + return -EOPNOTSUPP; + } + case hwmon_temp_crit: + switch (channel) { + case CHANNEL_PKG: + *val = hwmon->temp.limit[TEMP_LIMIT_PKG_CRIT] * MILLIDEGREE_PER_DEGREE; + return 0; + case CHANNEL_VRAM: + *val = hwmon->temp.limit[TEMP_LIMIT_MEM_CRIT] * MILLIDEGREE_PER_DEGREE; + return 0; + default: + return -EOPNOTSUPP; + } + case hwmon_temp_max: + switch (channel) { + case CHANNEL_PKG: + *val = hwmon->temp.limit[TEMP_LIMIT_PKG_MAX] * MILLIDEGREE_PER_DEGREE; + return 0; + default: + return -EOPNOTSUPP; + } default: return -EOPNOTSUPP; } @@ -1263,6 +1356,9 @@ xe_hwmon_get_preregistration_info(struct xe_hwmon *hwmon) for (channel = 0; channel < FAN_MAX; channel++) if (xe_hwmon_is_visible(hwmon, hwmon_fan, hwmon_fan_input, channel)) xe_hwmon_fan_input_read(hwmon, channel, &fan_speed); + + if (hwmon->xe->info.has_mbx_thermal_info && xe_hwmon_pcode_read_thermal_info(hwmon)) + drm_warn(&hwmon->xe->drm, "Thermal mailbox not supported by card firmware\n"); } int xe_hwmon_register(struct xe_device *xe) diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index 673db1e82ec3..fa0a374d88f8 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -366,6 +366,7 @@ static const struct xe_device_desc bmg_desc = { .has_fan_control = true, .has_flat_ccs = 1, .has_mbx_power_limits = true, + .has_mbx_thermal_info = true, .has_gsc_nvm = 1, .has_heci_cscfi = 1, .has_i2c = true, @@ -422,6 +423,7 @@ static const struct xe_device_desc cri_desc = { .has_gsc_nvm = 1, .has_i2c = true, .has_mbx_power_limits = true, + .has_mbx_thermal_info = true, .has_mert = true, .has_pre_prod_wa = 1, .has_soc_remapper_sysctrl = true, @@ -687,6 +689,7 @@ static int xe_info_init_early(struct xe_device *xe, /* runtime fusing may force flat_ccs to disabled later */ xe->info.has_flat_ccs = desc->has_flat_ccs; xe->info.has_mbx_power_limits = desc->has_mbx_power_limits; + xe->info.has_mbx_thermal_info = desc->has_mbx_thermal_info; xe->info.has_gsc_nvm = desc->has_gsc_nvm; xe->info.has_heci_gscfi = desc->has_heci_gscfi; xe->info.has_heci_cscfi = desc->has_heci_cscfi; diff --git a/drivers/gpu/drm/xe/xe_pci_types.h b/drivers/gpu/drm/xe/xe_pci_types.h index 5f20f56571d1..20acc5349ee6 100644 --- a/drivers/gpu/drm/xe/xe_pci_types.h +++ b/drivers/gpu/drm/xe/xe_pci_types.h @@ -48,6 +48,7 @@ struct xe_device_desc { u8 has_late_bind:1; u8 has_llc:1; u8 has_mbx_power_limits:1; + u8 has_mbx_thermal_info:1; u8 has_mem_copy_instr:1; u8 has_mert:1; u8 has_pre_prod_wa:1; diff --git a/drivers/gpu/drm/xe/xe_pcode_api.h b/drivers/gpu/drm/xe/xe_pcode_api.h index 975892d6b230..dc8f241e5b9e 100644 --- a/drivers/gpu/drm/xe/xe_pcode_api.h +++ b/drivers/gpu/drm/xe/xe_pcode_api.h @@ -50,6 +50,9 @@ #define READ_PL_FROM_FW 0x1 #define READ_PL_FROM_PCODE 0x0 +#define PCODE_THERMAL_INFO 0x25 +#define READ_THERMAL_LIMITS 0x0 + #define PCODE_LATE_BINDING 0x5C #define GET_CAPABILITY_STATUS 0x0 #define V1_FAN_SUPPORTED REG_BIT(0) -- cgit v1.2.3 From 3a0cb885e111db34b22058a3b82e99e49f02ac94 Mon Sep 17 00:00:00 2001 From: Karthik Poosa Date: Tue, 13 Jan 2026 02:05:19 +0530 Subject: drm/xe/hwmon: Expose memory controller temperature Expose GPU memory controller average temperature and its limits under temp4_xxx. Update Xe hwmon documentation for this. v2: - Rephrase commit message. (Badal) - Update kernel version in Xe hwmon documentation. (Raag) v3: - Update kernel version in Xe hwmon documentation. - Address review comments from Raag. - Remove obvious comments. - Remove redundant debug logs. - Remove unnecessary checks. - Avoid magic numbers. - Add new comments. - Use temperature sensors count to make memory controller visible. - Use temperature limits of package for memory controller. v4: - Address review comments from Raag. - Group new temperature attributes with existing temperature attributes as per channel index in Xe hwmon documentation. - Use DIV_ROUND_UP to calculate dwords needed for temperature limits. - Minor aesthetic refinements. - Remove unused TEMP_MASK_MAILBOX. v5: - Use REG_FIELD_GET to get count from READ_THERMAL_DATA output. (Raag) - Change count print from decimal to hexadecimal. - Cosmetic changes. Signed-off-by: Karthik Poosa Reviewed-by: Raag Jadav Link: https://patch.msgid.link/20260112203521.1014388-3-karthik.poosa@intel.com Signed-off-by: Rodrigo Vivi --- .../ABI/testing/sysfs-driver-intel-xe-hwmon | 24 +++++++ drivers/gpu/drm/xe/xe_hwmon.c | 79 ++++++++++++++++++++-- drivers/gpu/drm/xe/xe_pcode_api.h | 2 + 3 files changed, 100 insertions(+), 5 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon index 2b00ef13b6ad..550206885624 100644 --- a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon +++ b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon @@ -165,6 +165,30 @@ Description: RO. VRAM temperature in millidegree Celsius. Only supported for particular Intel Xe graphics platforms. +What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon/temp4_crit +Date: January 2026 +KernelVersion: 7.0 +Contact: intel-xe@lists.freedesktop.org +Description: RO. Memory controller critical temperature in millidegree Celsius. + + Only supported for particular Intel Xe graphics platforms. + +What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon/temp4_emergency +Date: January 2026 +KernelVersion: 7.0 +Contact: intel-xe@lists.freedesktop.org +Description: RO. Memory controller shutdown temperature in millidegree Celsius. + + Only supported for particular Intel Xe graphics platforms. + +What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon/temp4_input +Date: January 2026 +KernelVersion: 7.0 +Contact: intel-xe@lists.freedesktop.org +Description: RO. Memory controller average temperature in millidegree Celsius. + + Only supported for particular Intel Xe graphics platforms. + What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon/fan1_input Date: March 2025 KernelVersion: 6.16 diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c index 7eb6a76fa217..51a2c23be99e 100644 --- a/drivers/gpu/drm/xe/xe_hwmon.c +++ b/drivers/gpu/drm/xe/xe_hwmon.c @@ -43,6 +43,7 @@ enum xe_hwmon_channel { CHANNEL_CARD, CHANNEL_PKG, CHANNEL_VRAM, + CHANNEL_MCTRL, CHANNEL_MAX, }; @@ -100,6 +101,9 @@ enum sensor_attr_power { */ #define PL_WRITE_MBX_TIMEOUT_MS (1) +/* Index of memory controller in READ_THERMAL_DATA output */ +#define TEMP_INDEX_MCTRL 2 + /** * struct xe_hwmon_energy_info - to accumulate energy */ @@ -130,6 +134,10 @@ struct xe_hwmon_thermal_info { /** @data: temperature limits in dwords */ u32 data[DIV_ROUND_UP(TEMP_LIMIT_MAX, sizeof(u32))]; }; + /** @count: no of temperature sensors available for the platform */ + u8 count; + /** @value: signed value from each sensor */ + s8 value[U8_MAX]; }; /** @@ -703,6 +711,7 @@ static const struct hwmon_channel_info * const hwmon_info[] = { HWMON_T_LABEL, HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_MAX, + HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL), HWMON_CHANNEL_INFO(power, HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_LABEL | HWMON_P_CRIT | HWMON_P_CAP, @@ -717,16 +726,51 @@ static const struct hwmon_channel_info * const hwmon_info[] = { static int xe_hwmon_pcode_read_thermal_info(struct xe_hwmon *hwmon) { struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe); + u32 config = 0; int ret; ret = xe_pcode_read(root_tile, PCODE_MBOX(PCODE_THERMAL_INFO, READ_THERMAL_LIMITS, 0), &hwmon->temp.data[0], &hwmon->temp.data[1]); + if (ret) + return ret; + drm_dbg(&hwmon->xe->drm, "thermal info read val 0x%x val1 0x%x\n", hwmon->temp.data[0], hwmon->temp.data[1]); + ret = xe_pcode_read(root_tile, PCODE_MBOX(PCODE_THERMAL_INFO, READ_THERMAL_CONFIG, 0), + &config, NULL); + if (ret) + return ret; + + drm_dbg(&hwmon->xe->drm, "thermal config count 0x%x\n", config); + hwmon->temp.count = REG_FIELD_GET(TEMP_MASK, config); + return ret; } +static int get_mc_temp(struct xe_hwmon *hwmon, long *val) +{ + struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe); + u32 *dword = (u32 *)hwmon->temp.value; + s32 average = 0; + int ret, i; + + for (i = 0; i < DIV_ROUND_UP(TEMP_LIMIT_MAX, sizeof(u32)); i++) { + ret = xe_pcode_read(root_tile, PCODE_MBOX(PCODE_THERMAL_INFO, READ_THERMAL_DATA, i), + (dword + i), NULL); + if (ret) + return ret; + drm_dbg(&hwmon->xe->drm, "thermal data for group %d val 0x%x\n", i, dword[i]); + } + + for (i = TEMP_INDEX_MCTRL; i < hwmon->temp.count - 1; i++) + average += hwmon->temp.value[i]; + + average /= (hwmon->temp.count - TEMP_INDEX_MCTRL - 1); + *val = average * MILLIDEGREE_PER_DEGREE; + return 0; +} + /* I1 is exposed as power_crit or as curr_crit depending on bit 31 */ static int xe_hwmon_pcode_read_i1(const struct xe_hwmon *hwmon, u32 *uval) { @@ -831,6 +875,8 @@ xe_hwmon_temp_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel) return hwmon->temp.limit[TEMP_LIMIT_PKG_SHUTDOWN] ? 0444 : 0; case CHANNEL_VRAM: return hwmon->temp.limit[TEMP_LIMIT_MEM_SHUTDOWN] ? 0444 : 0; + case CHANNEL_MCTRL: + return hwmon->temp.count ? 0444 : 0; default: return 0; } @@ -840,6 +886,8 @@ xe_hwmon_temp_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel) return hwmon->temp.limit[TEMP_LIMIT_PKG_CRIT] ? 0444 : 0; case CHANNEL_VRAM: return hwmon->temp.limit[TEMP_LIMIT_MEM_CRIT] ? 0444 : 0; + case CHANNEL_MCTRL: + return hwmon->temp.count ? 0444 : 0; default: return 0; } @@ -852,7 +900,16 @@ xe_hwmon_temp_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel) } case hwmon_temp_input: case hwmon_temp_label: - return xe_reg_is_valid(xe_hwmon_get_reg(hwmon, REG_TEMP, channel)) ? 0444 : 0; + switch (channel) { + case CHANNEL_PKG: + case CHANNEL_VRAM: + return xe_reg_is_valid(xe_hwmon_get_reg(hwmon, REG_TEMP, + channel)) ? 0444 : 0; + case CHANNEL_MCTRL: + return hwmon->temp.count ? 0444 : 0; + default: + return 0; + } default: return 0; } @@ -866,14 +923,23 @@ xe_hwmon_temp_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val) switch (attr) { case hwmon_temp_input: - reg_val = xe_mmio_read32(mmio, xe_hwmon_get_reg(hwmon, REG_TEMP, channel)); + switch (channel) { + case CHANNEL_PKG: + case CHANNEL_VRAM: + reg_val = xe_mmio_read32(mmio, xe_hwmon_get_reg(hwmon, REG_TEMP, channel)); - /* HW register value is in degrees Celsius, convert to millidegrees. */ - *val = REG_FIELD_GET(TEMP_MASK, reg_val) * MILLIDEGREE_PER_DEGREE; - return 0; + /* HW register value is in degrees Celsius, convert to millidegrees. */ + *val = REG_FIELD_GET(TEMP_MASK, reg_val) * MILLIDEGREE_PER_DEGREE; + return 0; + case CHANNEL_MCTRL: + return get_mc_temp(hwmon, val); + default: + return -EOPNOTSUPP; + } case hwmon_temp_emergency: switch (channel) { case CHANNEL_PKG: + case CHANNEL_MCTRL: *val = hwmon->temp.limit[TEMP_LIMIT_PKG_SHUTDOWN] * MILLIDEGREE_PER_DEGREE; return 0; case CHANNEL_VRAM: @@ -885,6 +951,7 @@ xe_hwmon_temp_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val) case hwmon_temp_crit: switch (channel) { case CHANNEL_PKG: + case CHANNEL_MCTRL: *val = hwmon->temp.limit[TEMP_LIMIT_PKG_CRIT] * MILLIDEGREE_PER_DEGREE; return 0; case CHANNEL_VRAM: @@ -1262,6 +1329,8 @@ static int xe_hwmon_read_label(struct device *dev, *str = "pkg"; else if (channel == CHANNEL_VRAM) *str = "vram"; + else if (channel == CHANNEL_MCTRL) + *str = "mctrl"; return 0; case hwmon_power: case hwmon_energy: diff --git a/drivers/gpu/drm/xe/xe_pcode_api.h b/drivers/gpu/drm/xe/xe_pcode_api.h index dc8f241e5b9e..ad713a3e34e5 100644 --- a/drivers/gpu/drm/xe/xe_pcode_api.h +++ b/drivers/gpu/drm/xe/xe_pcode_api.h @@ -52,6 +52,8 @@ #define PCODE_THERMAL_INFO 0x25 #define READ_THERMAL_LIMITS 0x0 +#define READ_THERMAL_CONFIG 0x1 +#define READ_THERMAL_DATA 0x2 #define PCODE_LATE_BINDING 0x5C #define GET_CAPABILITY_STATUS 0x0 -- cgit v1.2.3 From 8d2511686ef55cfbdcc14d2f051224c3a16741d6 Mon Sep 17 00:00:00 2001 From: Karthik Poosa Date: Tue, 13 Jan 2026 02:05:20 +0530 Subject: drm/xe/hwmon: Expose GPU PCIe temperature Expose GPU PCIe average temperature and its limits via hwmon sysfs entry temp5_xxx. Update Xe hwmon sysfs documentation for this. v2: Update kernel version in Xe hwmon documentation. (Raag) v3: - Address review comments from Raag. - Remove redundant debug log. - Update kernel version in Xe hwmon documentation. (Raag) v4: - Address review comments from Raag. - Group new temperature attributes with existing temperature attributes as per channel index in Xe hwmon documentation. - Use TEMP_MASK instead of TEMP_MASK_MAILBOX. - Add PCIE_SENSOR_MASK which uses REG_FIELD_GET as replacement of PCIE_SENSOR_SHIFT. v5: - Address review comments from Raag. - Use REG_FIELD_GET to get PCIe temperature. - Move PCIE_SENSOR_GROUP_ID and PCIE_SENSOR_MASK to xe_pcode_api.h - Cosmetic change. Signed-off-by: Karthik Poosa Reviewed-by: Raag Jadav Link: https://patch.msgid.link/20260112203521.1014388-4-karthik.poosa@intel.com Signed-off-by: Rodrigo Vivi --- .../ABI/testing/sysfs-driver-intel-xe-hwmon | 24 ++++++++++++++++ drivers/gpu/drm/xe/xe_hwmon.c | 32 ++++++++++++++++++++++ drivers/gpu/drm/xe/xe_pcode_api.h | 2 ++ 3 files changed, 58 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon index 550206885624..6e21bebf0e0d 100644 --- a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon +++ b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon @@ -189,6 +189,30 @@ Description: RO. Memory controller average temperature in millidegree Celsius. Only supported for particular Intel Xe graphics platforms. +What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon/temp5_crit +Date: January 2026 +KernelVersion: 7.0 +Contact: intel-xe@lists.freedesktop.org +Description: RO. GPU PCIe critical temperature in millidegree Celsius. + + Only supported for particular Intel Xe graphics platforms. + +What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon/temp5_emergency +Date: January 2026 +KernelVersion: 7.0 +Contact: intel-xe@lists.freedesktop.org +Description: RO. GPU PCIe shutdown temperature in millidegree Celsius. + + Only supported for particular Intel Xe graphics platforms. + +What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon/temp5_input +Date: January 2026 +KernelVersion: 7.0 +Contact: intel-xe@lists.freedesktop.org +Description: RO. GPU PCIe temperature in millidegree Celsius. + + Only supported for particular Intel Xe graphics platforms. + What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon/fan1_input Date: March 2025 KernelVersion: 6.16 diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c index 51a2c23be99e..e8604e6300ac 100644 --- a/drivers/gpu/drm/xe/xe_hwmon.c +++ b/drivers/gpu/drm/xe/xe_hwmon.c @@ -44,6 +44,7 @@ enum xe_hwmon_channel { CHANNEL_PKG, CHANNEL_VRAM, CHANNEL_MCTRL, + CHANNEL_PCIE, CHANNEL_MAX, }; @@ -712,6 +713,7 @@ static const struct hwmon_channel_info * const hwmon_info[] = { HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_MAX, HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL), HWMON_CHANNEL_INFO(power, HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_LABEL | HWMON_P_CRIT | HWMON_P_CAP, @@ -771,6 +773,27 @@ static int get_mc_temp(struct xe_hwmon *hwmon, long *val) return 0; } +static int get_pcie_temp(struct xe_hwmon *hwmon, long *val) +{ + struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe); + u32 data = 0; + int ret; + + ret = xe_pcode_read(root_tile, PCODE_MBOX(PCODE_THERMAL_INFO, READ_THERMAL_DATA, + PCIE_SENSOR_GROUP_ID), &data, NULL); + if (ret) + return ret; + + /* Sensor offset is different for G21 */ + if (hwmon->xe->info.subplatform != XE_SUBPLATFORM_BATTLEMAGE_G21) + data = REG_FIELD_GET(PCIE_SENSOR_MASK, data); + + data = REG_FIELD_GET(TEMP_MASK, data); + *val = (s8)data * MILLIDEGREE_PER_DEGREE; + + return 0; +} + /* I1 is exposed as power_crit or as curr_crit depending on bit 31 */ static int xe_hwmon_pcode_read_i1(const struct xe_hwmon *hwmon, u32 *uval) { @@ -876,6 +899,7 @@ xe_hwmon_temp_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel) case CHANNEL_VRAM: return hwmon->temp.limit[TEMP_LIMIT_MEM_SHUTDOWN] ? 0444 : 0; case CHANNEL_MCTRL: + case CHANNEL_PCIE: return hwmon->temp.count ? 0444 : 0; default: return 0; @@ -887,6 +911,7 @@ xe_hwmon_temp_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel) case CHANNEL_VRAM: return hwmon->temp.limit[TEMP_LIMIT_MEM_CRIT] ? 0444 : 0; case CHANNEL_MCTRL: + case CHANNEL_PCIE: return hwmon->temp.count ? 0444 : 0; default: return 0; @@ -906,6 +931,7 @@ xe_hwmon_temp_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel) return xe_reg_is_valid(xe_hwmon_get_reg(hwmon, REG_TEMP, channel)) ? 0444 : 0; case CHANNEL_MCTRL: + case CHANNEL_PCIE: return hwmon->temp.count ? 0444 : 0; default: return 0; @@ -933,6 +959,8 @@ xe_hwmon_temp_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val) return 0; case CHANNEL_MCTRL: return get_mc_temp(hwmon, val); + case CHANNEL_PCIE: + return get_pcie_temp(hwmon, val); default: return -EOPNOTSUPP; } @@ -940,6 +968,7 @@ xe_hwmon_temp_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val) switch (channel) { case CHANNEL_PKG: case CHANNEL_MCTRL: + case CHANNEL_PCIE: *val = hwmon->temp.limit[TEMP_LIMIT_PKG_SHUTDOWN] * MILLIDEGREE_PER_DEGREE; return 0; case CHANNEL_VRAM: @@ -952,6 +981,7 @@ xe_hwmon_temp_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val) switch (channel) { case CHANNEL_PKG: case CHANNEL_MCTRL: + case CHANNEL_PCIE: *val = hwmon->temp.limit[TEMP_LIMIT_PKG_CRIT] * MILLIDEGREE_PER_DEGREE; return 0; case CHANNEL_VRAM: @@ -1331,6 +1361,8 @@ static int xe_hwmon_read_label(struct device *dev, *str = "vram"; else if (channel == CHANNEL_MCTRL) *str = "mctrl"; + else if (channel == CHANNEL_PCIE) + *str = "pcie"; return 0; case hwmon_power: case hwmon_energy: diff --git a/drivers/gpu/drm/xe/xe_pcode_api.h b/drivers/gpu/drm/xe/xe_pcode_api.h index ad713a3e34e5..85cc7478b787 100644 --- a/drivers/gpu/drm/xe/xe_pcode_api.h +++ b/drivers/gpu/drm/xe/xe_pcode_api.h @@ -54,6 +54,8 @@ #define READ_THERMAL_LIMITS 0x0 #define READ_THERMAL_CONFIG 0x1 #define READ_THERMAL_DATA 0x2 +#define PCIE_SENSOR_GROUP_ID 0x2 +#define PCIE_SENSOR_MASK REG_GENMASK(31, 16) #define PCODE_LATE_BINDING 0x5C #define GET_CAPABILITY_STATUS 0x0 -- cgit v1.2.3 From 49a498338417281f78594294c83707b140afde85 Mon Sep 17 00:00:00 2001 From: Karthik Poosa Date: Tue, 13 Jan 2026 02:05:21 +0530 Subject: drm/xe/hwmon: Expose individual VRAM channel temperature Expose individual VRAM temperature attributes. Update Xe hwmon documentation for this entry. v2: - Avoid using default switch case for VRAM individual temperatures. - Append labels with VRAM channel number. - Update kernel version in Xe hwmon documentation. v3: - Add missing brackets in Xe hwmon documentation from VRAM channel sysfs. - Reorder BMG_VRAM_TEMPERATURE_N macro in xe_pcode_regs.h. - Add api to check if VRAM is available on the channel. v4: - Improve VRAM label handling to eliminate temp variable by introducing a dedicated array vram_label in xe_hwmon_thermal_info. - Remove a magic number. - Change the label from vram_X to vram_ch_X. v5: - Address review comments from Raag. - Change vram to VRAM in commit title and subject. - Refactor BMG_VRAM_TEMPERATURE_N macro. - Refactor is_vram_ch_available(). - Rephrase a comment. - Check individual VRAM temperature limits in addition to VRAM availability in xe_hwmon_temp_is_visible. (Raag) - Move VRAM label change out of this patch. v6: - Use in_range() for VRAM_N index check instead of if check. (Raag) - Minor aesthetic changes. Signed-off-by: Karthik Poosa Reviewed-by: Raag Jadav Link: https://patch.msgid.link/20260112203521.1014388-5-karthik.poosa@intel.com Signed-off-by: Rodrigo Vivi --- .../ABI/testing/sysfs-driver-intel-xe-hwmon | 22 ++++++++ drivers/gpu/drm/xe/regs/xe_pcode_regs.h | 3 + drivers/gpu/drm/xe/xe_hwmon.c | 66 ++++++++++++++++++++++ 3 files changed, 91 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon index 6e21bebf0e0d..55ab45f669ac 100644 --- a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon +++ b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon @@ -211,6 +211,28 @@ KernelVersion: 7.0 Contact: intel-xe@lists.freedesktop.org Description: RO. GPU PCIe temperature in millidegree Celsius. +What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon/temp[6-21]_crit +Date: January 2026 +KernelVersion: 7.0 +Contact: intel-xe@lists.freedesktop.org +Description: RO. VRAM channel critical temperature in millidegree Celsius. + + Only supported for particular Intel Xe graphics platforms. + +What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon/temp[6-21]_emergency +Date: January 2026 +KernelVersion: 7.0 +Contact: intel-xe@lists.freedesktop.org +Description: RO. VRAM channel shutdown temperature in millidegree Celsius. + + Only supported for particular Intel Xe graphics platforms. + +What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon/temp[6-21]_input +Date: January 2026 +KernelVersion: 7.0 +Contact: intel-xe@lists.freedesktop.org +Description: RO. VRAM channel temperature in millidegree Celsius. + Only supported for particular Intel Xe graphics platforms. What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon/fan1_input diff --git a/drivers/gpu/drm/xe/regs/xe_pcode_regs.h b/drivers/gpu/drm/xe/regs/xe_pcode_regs.h index fb097607b86c..4b3c46eb858f 100644 --- a/drivers/gpu/drm/xe/regs/xe_pcode_regs.h +++ b/drivers/gpu/drm/xe/regs/xe_pcode_regs.h @@ -21,7 +21,10 @@ #define BMG_FAN_1_SPEED XE_REG(0x138140) #define BMG_FAN_2_SPEED XE_REG(0x138170) #define BMG_FAN_3_SPEED XE_REG(0x1381a0) +#define BMG_VRAM_TEMPERATURE_N(n) XE_REG(0x138260 + ((n) * (sizeof(u32)))) #define BMG_VRAM_TEMPERATURE XE_REG(0x1382c0) +#define TEMP_MASK_VRAM_N REG_GENMASK(30, 8) +#define TEMP_SIGN_MASK REG_BIT(31) #define BMG_PACKAGE_TEMPERATURE XE_REG(0x138434) #endif /* _XE_PCODE_REGS_H_ */ diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c index e8604e6300ac..baf277955b33 100644 --- a/drivers/gpu/drm/xe/xe_hwmon.c +++ b/drivers/gpu/drm/xe/xe_hwmon.c @@ -39,12 +39,16 @@ enum xe_hwmon_reg_operation { REG_READ64, }; +#define MAX_VRAM_CHANNELS (16) + enum xe_hwmon_channel { CHANNEL_CARD, CHANNEL_PKG, CHANNEL_VRAM, CHANNEL_MCTRL, CHANNEL_PCIE, + CHANNEL_VRAM_N, + CHANNEL_VRAM_N_MAX = CHANNEL_VRAM_N + MAX_VRAM_CHANNELS, CHANNEL_MAX, }; @@ -105,6 +109,9 @@ enum sensor_attr_power { /* Index of memory controller in READ_THERMAL_DATA output */ #define TEMP_INDEX_MCTRL 2 +/* Maximum characters in hwmon label name */ +#define MAX_LABEL_SIZE 16 + /** * struct xe_hwmon_energy_info - to accumulate energy */ @@ -139,6 +146,8 @@ struct xe_hwmon_thermal_info { u8 count; /** @value: signed value from each sensor */ s8 value[U8_MAX]; + /** @vram_label: vram label names */ + char vram_label[MAX_VRAM_CHANNELS][MAX_LABEL_SIZE]; }; /** @@ -255,6 +264,8 @@ static struct xe_reg xe_hwmon_get_reg(struct xe_hwmon *hwmon, enum xe_hwmon_reg return BMG_PACKAGE_TEMPERATURE; else if (channel == CHANNEL_VRAM) return BMG_VRAM_TEMPERATURE; + else if (in_range(channel, CHANNEL_VRAM_N, CHANNEL_VRAM_N_MAX)) + return BMG_VRAM_TEMPERATURE_N(channel - CHANNEL_VRAM_N); } else if (xe->info.platform == XE_DG2) { if (channel == CHANNEL_PKG) return PCU_CR_PACKAGE_TEMPERATURE; @@ -714,6 +725,22 @@ static const struct hwmon_channel_info * const hwmon_info[] = { HWMON_T_MAX, HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL), HWMON_CHANNEL_INFO(power, HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_LABEL | HWMON_P_CRIT | HWMON_P_CAP, @@ -888,6 +915,21 @@ static void xe_hwmon_get_voltage(struct xe_hwmon *hwmon, int channel, long *valu *value = DIV_ROUND_CLOSEST(REG_FIELD_GET(VOLTAGE_MASK, reg_val) * 2500, SF_VOLTAGE); } +static inline bool is_vram_ch_available(struct xe_hwmon *hwmon, int channel) +{ + struct xe_mmio *mmio = xe_root_tile_mmio(hwmon->xe); + int vram_id = channel - CHANNEL_VRAM_N; + struct xe_reg vram_reg; + + vram_reg = xe_hwmon_get_reg(hwmon, REG_TEMP, channel); + if (!xe_reg_is_valid(vram_reg) || !xe_mmio_read32(mmio, vram_reg)) + return false; + + /* Create label only for available vram channel */ + sprintf(hwmon->temp.vram_label[vram_id], "vram_ch_%d", vram_id); + return true; +} + static umode_t xe_hwmon_temp_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel) { @@ -901,6 +943,9 @@ xe_hwmon_temp_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel) case CHANNEL_MCTRL: case CHANNEL_PCIE: return hwmon->temp.count ? 0444 : 0; + case CHANNEL_VRAM_N...CHANNEL_VRAM_N_MAX: + return (is_vram_ch_available(hwmon, channel) && + hwmon->temp.limit[TEMP_LIMIT_MEM_SHUTDOWN]) ? 0444 : 0; default: return 0; } @@ -913,6 +958,9 @@ xe_hwmon_temp_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel) case CHANNEL_MCTRL: case CHANNEL_PCIE: return hwmon->temp.count ? 0444 : 0; + case CHANNEL_VRAM_N...CHANNEL_VRAM_N_MAX: + return (is_vram_ch_available(hwmon, channel) && + hwmon->temp.limit[TEMP_LIMIT_MEM_CRIT]) ? 0444 : 0; default: return 0; } @@ -933,6 +981,8 @@ xe_hwmon_temp_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel) case CHANNEL_MCTRL: case CHANNEL_PCIE: return hwmon->temp.count ? 0444 : 0; + case CHANNEL_VRAM_N...CHANNEL_VRAM_N_MAX: + return is_vram_ch_available(hwmon, channel) ? 0444 : 0; default: return 0; } @@ -961,6 +1011,16 @@ xe_hwmon_temp_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val) return get_mc_temp(hwmon, val); case CHANNEL_PCIE: return get_pcie_temp(hwmon, val); + case CHANNEL_VRAM_N...CHANNEL_VRAM_N_MAX: + reg_val = xe_mmio_read32(mmio, xe_hwmon_get_reg(hwmon, REG_TEMP, channel)); + /* + * This temperature format is 24 bit [31:8] signed integer and 8 bit + * [7:0] fraction. + */ + *val = (s32)(REG_FIELD_GET(TEMP_MASK_VRAM_N, reg_val)) * + (REG_FIELD_GET(TEMP_SIGN_MASK, reg_val) ? -1 : 1) * + MILLIDEGREE_PER_DEGREE; + return 0; default: return -EOPNOTSUPP; } @@ -972,6 +1032,7 @@ xe_hwmon_temp_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val) *val = hwmon->temp.limit[TEMP_LIMIT_PKG_SHUTDOWN] * MILLIDEGREE_PER_DEGREE; return 0; case CHANNEL_VRAM: + case CHANNEL_VRAM_N...CHANNEL_VRAM_N_MAX: *val = hwmon->temp.limit[TEMP_LIMIT_MEM_SHUTDOWN] * MILLIDEGREE_PER_DEGREE; return 0; default: @@ -985,6 +1046,7 @@ xe_hwmon_temp_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val) *val = hwmon->temp.limit[TEMP_LIMIT_PKG_CRIT] * MILLIDEGREE_PER_DEGREE; return 0; case CHANNEL_VRAM: + case CHANNEL_VRAM_N...CHANNEL_VRAM_N_MAX: *val = hwmon->temp.limit[TEMP_LIMIT_MEM_CRIT] * MILLIDEGREE_PER_DEGREE; return 0; default: @@ -1353,6 +1415,8 @@ static int xe_hwmon_read_label(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, const char **str) { + struct xe_hwmon *hwmon = dev_get_drvdata(dev); + switch (type) { case hwmon_temp: if (channel == CHANNEL_PKG) @@ -1363,6 +1427,8 @@ static int xe_hwmon_read_label(struct device *dev, *str = "mctrl"; else if (channel == CHANNEL_PCIE) *str = "pcie"; + else if (in_range(channel, CHANNEL_VRAM_N, CHANNEL_VRAM_N_MAX)) + *str = hwmon->temp.vram_label[channel - CHANNEL_VRAM_N]; return 0; case hwmon_power: case hwmon_energy: -- cgit v1.2.3 From a3753a331989d84024dcc0e3f301e4d0ebf4fda1 Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Mon, 12 Jan 2026 10:44:06 +0100 Subject: drm/xe: Replace use of system_wq with tlb_inval->timeout_wq This patch continues the effort to refactor workqueue APIs, which has begun with the changes introducing new workqueues and a new alloc_workqueue flag: commit 128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq") commit 930c2ea566af ("workqueue: Add new WQ_PERCPU flag") The point of the refactoring is to eventually alter the default behavior of workqueues to become unbound by default so that their workload placement is optimized by the scheduler. Before that to happen, workqueue users must be converted to the better named new workqueues with no intended behaviour changes: system_wq -> system_percpu_wq system_unbound_wq -> system_dfl_wq This way the old obsolete workqueues (system_wq, system_unbound_wq) can be removed in the future. After a carefully evaluation, because this is the fence signaling path, we changed the code in order to use one of the Xe's workqueue. So, a new workqueue named 'timeout_wq' has been added to 'struct xe_tlb_inval' and has been initialized with 'gt->ordered_wq' changing the system_wq uses with tlb_inval->timeout_wq. Link: https://lore.kernel.org/all/20250221112003.1dSuoGyc@linutronix.de/ Suggested-by: Tejun Heo Signed-off-by: Marco Crivellari Reviewed-by: Matthew Brost Signed-off-by: Matthew Brost Link: https://patch.msgid.link/20260112094406.82641-1-marco.crivellari@suse.com --- drivers/gpu/drm/xe/xe_tlb_inval.c | 10 +++++++--- drivers/gpu/drm/xe/xe_tlb_inval_types.h | 2 ++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_tlb_inval.c b/drivers/gpu/drm/xe/xe_tlb_inval.c index dec042248164..61b99cf0a733 100644 --- a/drivers/gpu/drm/xe/xe_tlb_inval.c +++ b/drivers/gpu/drm/xe/xe_tlb_inval.c @@ -94,7 +94,7 @@ static void xe_tlb_inval_fence_timeout(struct work_struct *work) xe_tlb_inval_fence_signal(fence); } if (!list_empty(&tlb_inval->pending_fences)) - queue_delayed_work(system_wq, &tlb_inval->fence_tdr, + queue_delayed_work(tlb_inval->timeout_wq, &tlb_inval->fence_tdr, timeout_delay); spin_unlock_irq(&tlb_inval->pending_lock); } @@ -146,6 +146,10 @@ int xe_gt_tlb_inval_init_early(struct xe_gt *gt) if (IS_ERR(tlb_inval->job_wq)) return PTR_ERR(tlb_inval->job_wq); + tlb_inval->timeout_wq = gt->ordered_wq; + if (IS_ERR(tlb_inval->timeout_wq)) + return PTR_ERR(tlb_inval->timeout_wq); + /* XXX: Blindly setting up backend to GuC */ xe_guc_tlb_inval_init_early(>->uc.guc, tlb_inval); @@ -240,7 +244,7 @@ static void xe_tlb_inval_fence_prep(struct xe_tlb_inval_fence *fence) list_add_tail(&fence->link, &tlb_inval->pending_fences); if (list_is_singular(&tlb_inval->pending_fences)) - queue_delayed_work(system_wq, &tlb_inval->fence_tdr, + queue_delayed_work(tlb_inval->timeout_wq, &tlb_inval->fence_tdr, tlb_inval->ops->timeout_delay(tlb_inval)); spin_unlock_irq(&tlb_inval->pending_lock); @@ -399,7 +403,7 @@ void xe_tlb_inval_done_handler(struct xe_tlb_inval *tlb_inval, int seqno) } if (!list_empty(&tlb_inval->pending_fences)) - mod_delayed_work(system_wq, + mod_delayed_work(tlb_inval->timeout_wq, &tlb_inval->fence_tdr, tlb_inval->ops->timeout_delay(tlb_inval)); else diff --git a/drivers/gpu/drm/xe/xe_tlb_inval_types.h b/drivers/gpu/drm/xe/xe_tlb_inval_types.h index 48d1503e8460..3b089f90f002 100644 --- a/drivers/gpu/drm/xe/xe_tlb_inval_types.h +++ b/drivers/gpu/drm/xe/xe_tlb_inval_types.h @@ -109,6 +109,8 @@ struct xe_tlb_inval { struct workqueue_struct *job_wq; /** @tlb_inval.lock: protects TLB invalidation fences */ spinlock_t lock; + /** @timeout_wq: schedules TLB invalidation fence timeouts */ + struct workqueue_struct *timeout_wq; }; /** -- cgit v1.2.3 From 6b2ff1d7c57ef49cd17ffe132173e05ab11a5213 Mon Sep 17 00:00:00 2001 From: Fei Yang Date: Mon, 12 Jan 2026 14:03:30 -0800 Subject: drm/xe: vram addr range is expanded to bit[17:8] The bit field used to be [14:8] with [17:15] marked as SPARE and defaulted to 0. So, simply expand the read to bit[17:8] assuming the platforms using only bit[14:8] have zeros in the expanded bits. BSpec: 54991 Signed-off-by: Fei Yang Reviewed-by: Matthew Brost Signed-off-by: Matthew Brost Link: https://patch.msgid.link/20260112220330.2267122-2-fei.yang@intel.com --- drivers/gpu/drm/xe/xe_vram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_vram.c b/drivers/gpu/drm/xe/xe_vram.c index c64d98bf1723..4f807eade2b7 100644 --- a/drivers/gpu/drm/xe/xe_vram.c +++ b/drivers/gpu/drm/xe/xe_vram.c @@ -155,7 +155,7 @@ static int tile_vram_size(struct xe_tile *tile, u64 *vram_size, *tile_offset = 0; } else { reg = xe_mmio_read32(&tile->mmio, SG_TILE_ADDR_RANGE(tile->id)); - *tile_size = (u64)REG_FIELD_GET(GENMASK(14, 8), reg) * SZ_1G; + *tile_size = (u64)REG_FIELD_GET(GENMASK(17, 8), reg) * SZ_1G; *tile_offset = (u64)REG_FIELD_GET(GENMASK(7, 1), reg) * SZ_1G; } -- cgit v1.2.3 From def675cf3f107ba8da78ca0b8650997fdf667538 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 12 Jan 2026 19:37:16 +0100 Subject: drm/xe/mert: Improve handling of MERT CAT errors All MERT catastrophic errors but VF's LMTT fault are serious, so we shouldn't limit our handling only to print debug messages. Change CATERR message to error level and then declare the device as wedged to match expectation from the design document. For the LMTT faults, add a note about adding tracking of this unexpected VF activity. While at it, rename register fields defnitions to match the BSpec. Also drop trailing include guard name from the regs.h file. BSpec: 74625 Signed-off-by: Michal Wajdeczko Cc: Lukasz Laguna Reviewed-by: Lukasz Laguna Link: https://patch.msgid.link/20260112183716.28700-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/regs/xe_mert_regs.h | 10 ++++---- drivers/gpu/drm/xe/xe_mert.c | 43 ++++++++++++++++++++++++++-------- 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/xe/regs/xe_mert_regs.h b/drivers/gpu/drm/xe/regs/xe_mert_regs.h index c345e11ceea8..99e5a26da657 100644 --- a/drivers/gpu/drm/xe/regs/xe_mert_regs.h +++ b/drivers/gpu/drm/xe/regs/xe_mert_regs.h @@ -11,11 +11,13 @@ #define MERT_LMEM_CFG XE_REG(0x1448b0) #define MERT_TLB_CT_INTR_ERR_ID_PORT XE_REG(0x145190) -#define MERT_TLB_CT_VFID_MASK REG_GENMASK(16, 9) -#define MERT_TLB_CT_ERROR_MASK REG_GENMASK(5, 0) -#define MERT_TLB_CT_LMTT_FAULT 0x05 +#define CATERR_VFID REG_GENMASK(16, 9) +#define CATERR_CODES REG_GENMASK(5, 0) +#define CATERR_NO_ERROR 0x00 +#define CATERR_UNMAPPED_GGTT 0x01 +#define CATERR_LMTT_FAULT 0x05 #define MERT_TLB_INV_DESC_A XE_REG(0x14cf7c) #define MERT_TLB_INV_DESC_A_VALID REG_BIT(0) -#endif /* _XE_MERT_REGS_H_ */ +#endif diff --git a/drivers/gpu/drm/xe/xe_mert.c b/drivers/gpu/drm/xe/xe_mert.c index fc027d2d7a5e..f637df95418b 100644 --- a/drivers/gpu/drm/xe/xe_mert.c +++ b/drivers/gpu/drm/xe/xe_mert.c @@ -9,6 +9,7 @@ #include "xe_device.h" #include "xe_mert.h" #include "xe_mmio.h" +#include "xe_sriov_printk.h" #include "xe_tile.h" /** @@ -55,6 +56,37 @@ int xe_mert_invalidate_lmtt(struct xe_device *xe) return 0; } +static void mert_handle_cat_error(struct xe_device *xe) +{ + struct xe_tile *tile = xe_device_get_root_tile(xe); + u32 reg_val, vfid, code; + + reg_val = xe_mmio_read32(&tile->mmio, MERT_TLB_CT_INTR_ERR_ID_PORT); + if (!reg_val) + return; + xe_mmio_write32(&tile->mmio, MERT_TLB_CT_INTR_ERR_ID_PORT, 0); + + vfid = FIELD_GET(CATERR_VFID, reg_val); + code = FIELD_GET(CATERR_CODES, reg_val); + + switch (code) { + case CATERR_NO_ERROR: + break; + case CATERR_UNMAPPED_GGTT: + xe_sriov_err(xe, "MERT: CAT_ERR: Access to an unmapped GGTT!\n"); + xe_device_declare_wedged(xe); + break; + case CATERR_LMTT_FAULT: + xe_sriov_dbg(xe, "MERT: CAT_ERR: VF%u LMTT fault!\n", vfid); + /* XXX: track/report malicious VF activity */ + break; + default: + xe_sriov_err(xe, "MERT: Unexpected CAT_ERR code=%#x!\n", code); + xe_device_declare_wedged(xe); + break; + } +} + /** * xe_mert_irq_handler - Handler for MERT interrupts * @xe: the &xe_device @@ -68,20 +100,11 @@ void xe_mert_irq_handler(struct xe_device *xe, u32 master_ctl) struct xe_mert *mert = &tile->mert; unsigned long flags; u32 reg_val; - u8 err; if (!(master_ctl & SOC_H2DMEMINT_IRQ)) return; - reg_val = xe_mmio_read32(&tile->mmio, MERT_TLB_CT_INTR_ERR_ID_PORT); - xe_mmio_write32(&tile->mmio, MERT_TLB_CT_INTR_ERR_ID_PORT, 0); - - err = FIELD_GET(MERT_TLB_CT_ERROR_MASK, reg_val); - if (err == MERT_TLB_CT_LMTT_FAULT) - drm_dbg(&xe->drm, "MERT catastrophic error: LMTT fault (VF%u)\n", - FIELD_GET(MERT_TLB_CT_VFID_MASK, reg_val)); - else if (err) - drm_dbg(&xe->drm, "MERT catastrophic error: Unexpected fault (0x%x)\n", err); + mert_handle_cat_error(xe); spin_lock_irqsave(&mert->lock, flags); if (mert->tlb_inv_triggered) { -- cgit v1.2.3 From 83675851547e835c15252c601f41acf269c351d9 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Wed, 14 Jan 2026 19:28:02 -0800 Subject: drm/xe: Cleanup unused header includes clangd reports many "unused header" warnings throughout the Xe driver. Start working to clean this up by removing unnecessary includes in our .c files and/or replacing them with explicit includes of other headers that were previously being included indirectly. By far the most common offender here was unnecessary inclusion of xe_gt.h. That likely originates from the early days of xe.ko when xe_mmio did not exist and all register accesses, including those unrelated to GTs, were done with GT functions. There's still a lot of additional #include cleanup that can be done in the headers themselves; that will come as a followup series. v2: - Squash the 79-patch series down to a single patch. (MattB) Reviewed-by: Matthew Brost Link: https://patch.msgid.link/20260115032803.4067824-2-matthew.d.roper@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/tests/xe_bo.c | 1 + drivers/gpu/drm/xe/xe_bb.c | 3 +-- drivers/gpu/drm/xe/xe_bo.c | 1 - drivers/gpu/drm/xe/xe_devcoredump.c | 3 +-- drivers/gpu/drm/xe/xe_device.c | 1 - drivers/gpu/drm/xe/xe_exec.c | 1 - drivers/gpu/drm/xe/xe_exec_queue.c | 2 -- drivers/gpu/drm/xe/xe_execlist.c | 3 +-- drivers/gpu/drm/xe/xe_ggtt.c | 3 +-- drivers/gpu/drm/xe/xe_gsc_debugfs.c | 5 ++--- drivers/gpu/drm/xe/xe_gsc_proxy.c | 2 +- drivers/gpu/drm/xe/xe_gsc_submit.c | 2 -- drivers/gpu/drm/xe/xe_gt.c | 2 -- drivers/gpu/drm/xe/xe_gt_clock.c | 6 +----- drivers/gpu/drm/xe/xe_gt_debugfs.c | 1 - drivers/gpu/drm/xe/xe_gt_idle.c | 1 - drivers/gpu/drm/xe/xe_gt_mcr.c | 1 - drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c | 2 -- drivers/gpu/drm/xe/xe_gt_sriov_pf_debugfs.c | 1 - drivers/gpu/drm/xe/xe_gt_sriov_pf_migration.c | 2 +- drivers/gpu/drm/xe/xe_gt_sriov_pf_policy.c | 1 - drivers/gpu/drm/xe/xe_gt_sriov_pf_service.c | 5 ++--- drivers/gpu/drm/xe/xe_gt_sriov_vf.c | 1 - drivers/gpu/drm/xe/xe_gt_stats.c | 2 +- drivers/gpu/drm/xe/xe_gt_sysfs.c | 2 +- drivers/gpu/drm/xe/xe_gt_throttle.c | 2 +- drivers/gpu/drm/xe/xe_guc_ads.c | 2 -- drivers/gpu/drm/xe/xe_guc_buf.c | 1 - drivers/gpu/drm/xe/xe_guc_capture.c | 5 +---- drivers/gpu/drm/xe/xe_guc_debugfs.c | 5 ++--- drivers/gpu/drm/xe/xe_guc_hwconfig.c | 4 ++-- drivers/gpu/drm/xe/xe_guc_log.c | 2 +- drivers/gpu/drm/xe/xe_guc_relay.c | 3 +-- drivers/gpu/drm/xe/xe_guc_submit.c | 2 -- drivers/gpu/drm/xe/xe_heci_gsc.c | 1 - drivers/gpu/drm/xe/xe_huc.c | 1 - drivers/gpu/drm/xe/xe_huc_debugfs.c | 5 ++--- drivers/gpu/drm/xe/xe_hw_engine.c | 1 - drivers/gpu/drm/xe/xe_hw_engine_class_sysfs.c | 2 +- drivers/gpu/drm/xe/xe_hw_engine_group.c | 2 +- drivers/gpu/drm/xe/xe_hw_fence.c | 4 +--- drivers/gpu/drm/xe/xe_i2c.c | 4 ++-- drivers/gpu/drm/xe/xe_irq.c | 1 - drivers/gpu/drm/xe/xe_memirq.c | 2 -- drivers/gpu/drm/xe/xe_mmio.c | 4 ---- drivers/gpu/drm/xe/xe_mocs.c | 2 -- drivers/gpu/drm/xe/xe_module.c | 2 +- drivers/gpu/drm/xe/xe_nvm.c | 1 - drivers/gpu/drm/xe/xe_page_reclaim.c | 4 ---- drivers/gpu/drm/xe/xe_pci.c | 1 - drivers/gpu/drm/xe/xe_psmi.c | 2 +- drivers/gpu/drm/xe/xe_pxp.c | 1 - drivers/gpu/drm/xe/xe_pxp_debugfs.c | 2 +- drivers/gpu/drm/xe/xe_reg_sr.c | 5 +---- drivers/gpu/drm/xe/xe_reg_whitelist.c | 1 - drivers/gpu/drm/xe/xe_ring_ops.c | 4 +--- drivers/gpu/drm/xe/xe_rtp.c | 1 - drivers/gpu/drm/xe/xe_sa.c | 2 +- drivers/gpu/drm/xe/xe_sched_job.c | 2 +- drivers/gpu/drm/xe/xe_sriov_packet.c | 1 - drivers/gpu/drm/xe/xe_sriov_pf_debugfs.c | 1 - drivers/gpu/drm/xe/xe_sriov_vf.c | 1 - drivers/gpu/drm/xe/xe_step.c | 3 ++- drivers/gpu/drm/xe/xe_survivability_mode.c | 1 - drivers/gpu/drm/xe/xe_tile.c | 3 +-- drivers/gpu/drm/xe/xe_tlb_inval.c | 7 ++----- drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c | 1 - drivers/gpu/drm/xe/xe_ttm_sys_mgr.c | 1 - drivers/gpu/drm/xe/xe_ttm_vram_mgr.c | 1 - drivers/gpu/drm/xe/xe_uc.c | 2 -- drivers/gpu/drm/xe/xe_uc_debugfs.c | 2 +- drivers/gpu/drm/xe/xe_uc_fw.c | 2 +- drivers/gpu/drm/xe/xe_validation.c | 1 - drivers/gpu/drm/xe/xe_vm.c | 1 - drivers/gpu/drm/xe/xe_vram.c | 2 -- drivers/gpu/drm/xe/xe_vram_freq.c | 1 - drivers/gpu/drm/xe/xe_vsec.c | 1 - drivers/gpu/drm/xe/xe_wa.c | 2 +- drivers/gpu/drm/xe/xe_wait_user_fence.c | 1 - drivers/gpu/drm/xe/xe_wopcm.c | 2 +- 80 files changed, 45 insertions(+), 129 deletions(-) diff --git a/drivers/gpu/drm/xe/tests/xe_bo.c b/drivers/gpu/drm/xe/tests/xe_bo.c index 2278e589a493..b7d8e45804cf 100644 --- a/drivers/gpu/drm/xe/tests/xe_bo.c +++ b/drivers/gpu/drm/xe/tests/xe_bo.c @@ -18,6 +18,7 @@ #include "tests/xe_test.h" #include "xe_bo_evict.h" +#include "xe_gt.h" #include "xe_pci.h" #include "xe_pm.h" diff --git a/drivers/gpu/drm/xe/xe_bb.c b/drivers/gpu/drm/xe/xe_bb.c index 6d20229c11de..8b678297aaa2 100644 --- a/drivers/gpu/drm/xe/xe_bb.c +++ b/drivers/gpu/drm/xe/xe_bb.c @@ -7,10 +7,9 @@ #include "instructions/xe_mi_commands.h" #include "xe_assert.h" -#include "xe_device.h" +#include "xe_device_types.h" #include "xe_exec_queue_types.h" #include "xe_gt.h" -#include "xe_hw_fence.h" #include "xe_sa.h" #include "xe_sched_job.h" #include "xe_vm_types.h" diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index 917e50c276ac..e9180b01a4e4 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -26,7 +26,6 @@ #include "xe_dma_buf.h" #include "xe_drm_client.h" #include "xe_ggtt.h" -#include "xe_gt.h" #include "xe_map.h" #include "xe_migrate.h" #include "xe_pat.h" diff --git a/drivers/gpu/drm/xe/xe_devcoredump.c b/drivers/gpu/drm/xe/xe_devcoredump.c index 7263c2a5f3a8..cf41bb6d2172 100644 --- a/drivers/gpu/drm/xe/xe_devcoredump.c +++ b/drivers/gpu/drm/xe/xe_devcoredump.c @@ -15,14 +15,13 @@ #include "xe_device.h" #include "xe_exec_queue.h" #include "xe_force_wake.h" -#include "xe_gt.h" #include "xe_gt_printk.h" +#include "xe_gt_types.h" #include "xe_guc_capture.h" #include "xe_guc_ct.h" #include "xe_guc_log.h" #include "xe_guc_submit.h" #include "xe_hw_engine.h" -#include "xe_module.h" #include "xe_pm.h" #include "xe_sched_job.h" #include "xe_vm.h" diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 7190b208e3da..495310a624b5 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -35,7 +35,6 @@ #include "xe_exec_queue.h" #include "xe_force_wake.h" #include "xe_ggtt.h" -#include "xe_gsc_proxy.h" #include "xe_gt.h" #include "xe_gt_mcr.h" #include "xe_gt_printk.h" diff --git a/drivers/gpu/drm/xe/xe_exec.c b/drivers/gpu/drm/xe/xe_exec.c index 730a5c9c2637..a5485fe6e3f1 100644 --- a/drivers/gpu/drm/xe/xe_exec.c +++ b/drivers/gpu/drm/xe/xe_exec.c @@ -11,7 +11,6 @@ #include #include -#include "xe_bo.h" #include "xe_device.h" #include "xe_exec_queue.h" #include "xe_hw_engine_group.h" diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c index b5737563ee14..a940849bb6c7 100644 --- a/drivers/gpu/drm/xe/xe_exec_queue.c +++ b/drivers/gpu/drm/xe/xe_exec_queue.c @@ -21,13 +21,11 @@ #include "xe_gt_sriov_vf.h" #include "xe_hw_engine_class_sysfs.h" #include "xe_hw_engine_group.h" -#include "xe_hw_fence.h" #include "xe_irq.h" #include "xe_lrc.h" #include "xe_macros.h" #include "xe_migrate.h" #include "xe_pm.h" -#include "xe_ring_ops_types.h" #include "xe_trace.h" #include "xe_vm.h" #include "xe_pxp.h" diff --git a/drivers/gpu/drm/xe/xe_execlist.c b/drivers/gpu/drm/xe/xe_execlist.c index 46c17a18a3f4..8bf330aeaec0 100644 --- a/drivers/gpu/drm/xe/xe_execlist.c +++ b/drivers/gpu/drm/xe/xe_execlist.c @@ -15,8 +15,7 @@ #include "xe_bo.h" #include "xe_device.h" #include "xe_exec_queue.h" -#include "xe_gt.h" -#include "xe_hw_fence.h" +#include "xe_gt_types.h" #include "xe_irq.h" #include "xe_lrc.h" #include "xe_macros.h" diff --git a/drivers/gpu/drm/xe/xe_ggtt.c b/drivers/gpu/drm/xe/xe_ggtt.c index cb23d97845a8..60665ad1415b 100644 --- a/drivers/gpu/drm/xe/xe_ggtt.c +++ b/drivers/gpu/drm/xe/xe_ggtt.c @@ -20,9 +20,8 @@ #include "regs/xe_regs.h" #include "xe_assert.h" #include "xe_bo.h" -#include "xe_device.h" -#include "xe_gt.h" #include "xe_gt_printk.h" +#include "xe_gt_types.h" #include "xe_map.h" #include "xe_mmio.h" #include "xe_pm.h" diff --git a/drivers/gpu/drm/xe/xe_gsc_debugfs.c b/drivers/gpu/drm/xe/xe_gsc_debugfs.c index b13928b50eb9..d4977e666946 100644 --- a/drivers/gpu/drm/xe/xe_gsc_debugfs.c +++ b/drivers/gpu/drm/xe/xe_gsc_debugfs.c @@ -7,11 +7,10 @@ #include #include +#include -#include "xe_device.h" -#include "xe_gt.h" +#include "xe_gt_types.h" #include "xe_gsc.h" -#include "xe_macros.h" #include "xe_pm.h" static struct xe_gt * diff --git a/drivers/gpu/drm/xe/xe_gsc_proxy.c b/drivers/gpu/drm/xe/xe_gsc_proxy.c index e7573a0c5e5d..42438b21f235 100644 --- a/drivers/gpu/drm/xe/xe_gsc_proxy.c +++ b/drivers/gpu/drm/xe/xe_gsc_proxy.c @@ -18,8 +18,8 @@ #include "xe_force_wake.h" #include "xe_gsc.h" #include "xe_gsc_submit.h" -#include "xe_gt.h" #include "xe_gt_printk.h" +#include "xe_gt_types.h" #include "xe_map.h" #include "xe_mmio.h" #include "xe_pm.h" diff --git a/drivers/gpu/drm/xe/xe_gsc_submit.c b/drivers/gpu/drm/xe/xe_gsc_submit.c index 9ede483d37ef..08082b596501 100644 --- a/drivers/gpu/drm/xe/xe_gsc_submit.c +++ b/drivers/gpu/drm/xe/xe_gsc_submit.c @@ -11,12 +11,10 @@ #include "xe_assert.h" #include "xe_bb.h" #include "xe_exec_queue.h" -#include "xe_gt_printk.h" #include "xe_gt_types.h" #include "xe_map.h" #include "xe_sched_job.h" #include "instructions/xe_gsc_commands.h" -#include "regs/xe_gsc_regs.h" #define GSC_HDR_SIZE (sizeof(struct intel_gsc_mtl_header)) /* shorthand define */ diff --git a/drivers/gpu/drm/xe/xe_gt.c b/drivers/gpu/drm/xe/xe_gt.c index 04dbf995a18b..9d090d0f2438 100644 --- a/drivers/gpu/drm/xe/xe_gt.c +++ b/drivers/gpu/drm/xe/xe_gt.c @@ -13,13 +13,11 @@ #include #include "instructions/xe_alu_commands.h" -#include "instructions/xe_gfxpipe_commands.h" #include "instructions/xe_mi_commands.h" #include "regs/xe_engine_regs.h" #include "regs/xe_gt_regs.h" #include "xe_assert.h" #include "xe_bb.h" -#include "xe_bo.h" #include "xe_device.h" #include "xe_eu_stall.h" #include "xe_exec_queue.h" diff --git a/drivers/gpu/drm/xe/xe_gt_clock.c b/drivers/gpu/drm/xe/xe_gt_clock.c index bfc25c46f798..53b3835192da 100644 --- a/drivers/gpu/drm/xe/xe_gt_clock.c +++ b/drivers/gpu/drm/xe/xe_gt_clock.c @@ -8,12 +8,8 @@ #include "xe_gt_clock.h" #include "regs/xe_gt_regs.h" -#include "regs/xe_regs.h" -#include "xe_assert.h" -#include "xe_device.h" -#include "xe_gt.h" +#include "xe_gt_types.h" #include "xe_gt_printk.h" -#include "xe_macros.h" #include "xe_mmio.h" #define f19_2_mhz 19200000 diff --git a/drivers/gpu/drm/xe/xe_gt_debugfs.c b/drivers/gpu/drm/xe/xe_gt_debugfs.c index e4f38b5150fc..4363bc9c3606 100644 --- a/drivers/gpu/drm/xe/xe_gt_debugfs.c +++ b/drivers/gpu/drm/xe/xe_gt_debugfs.c @@ -22,7 +22,6 @@ #include "xe_guc_hwconfig.h" #include "xe_hw_engine.h" #include "xe_lrc.h" -#include "xe_macros.h" #include "xe_mocs.h" #include "xe_pat.h" #include "xe_pm.h" diff --git a/drivers/gpu/drm/xe/xe_gt_idle.c b/drivers/gpu/drm/xe/xe_gt_idle.c index c1c9bec3c487..7a569e1730a4 100644 --- a/drivers/gpu/drm/xe/xe_gt_idle.c +++ b/drivers/gpu/drm/xe/xe_gt_idle.c @@ -13,7 +13,6 @@ #include "xe_gt_sysfs.h" #include "xe_guc_pc.h" #include "regs/xe_gt_regs.h" -#include "xe_macros.h" #include "xe_mmio.h" #include "xe_pm.h" #include "xe_sriov.h" diff --git a/drivers/gpu/drm/xe/xe_gt_mcr.c b/drivers/gpu/drm/xe/xe_gt_mcr.c index 164010860664..7c1fe9ac120d 100644 --- a/drivers/gpu/drm/xe/xe_gt_mcr.c +++ b/drivers/gpu/drm/xe/xe_gt_mcr.c @@ -7,7 +7,6 @@ #include "regs/xe_gt_regs.h" #include "xe_assert.h" -#include "xe_gt.h" #include "xe_gt_printk.h" #include "xe_gt_topology.h" #include "xe_gt_types.h" diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c index 9f2525f3cb37..23601ce79348 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c @@ -24,13 +24,11 @@ #include "xe_guc_buf.h" #include "xe_guc_ct.h" #include "xe_guc_db_mgr.h" -#include "xe_guc_fwif.h" #include "xe_guc_id_mgr.h" #include "xe_guc_klv_helpers.h" #include "xe_guc_klv_thresholds_set.h" #include "xe_guc_submit.h" #include "xe_lmtt.h" -#include "xe_map.h" #include "xe_migrate.h" #include "xe_sriov.h" #include "xe_ttm_vram_mgr.h" diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_debugfs.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf_debugfs.c index 47d288c53539..f97abb02aebd 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_debugfs.c +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_debugfs.c @@ -8,7 +8,6 @@ #include #include -#include "xe_bo.h" #include "xe_debugfs.h" #include "xe_device.h" #include "xe_gt.h" diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_migration.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf_migration.c index 7410e7b93256..87a164efcc33 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_migration.c +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_migration.c @@ -14,7 +14,6 @@ #include "xe_gt_sriov_pf.h" #include "xe_gt_sriov_pf_config.h" #include "xe_gt_sriov_pf_control.h" -#include "xe_gt_sriov_pf_helpers.h" #include "xe_gt_sriov_pf_migration.h" #include "xe_gt_sriov_printk.h" #include "xe_guc.h" @@ -25,6 +24,7 @@ #include "xe_sriov.h" #include "xe_sriov_packet.h" #include "xe_sriov_packet_types.h" +#include "xe_sriov_pf_helpers.h" #include "xe_sriov_pf_migration.h" #define XE_GT_SRIOV_PF_MIGRATION_RING_SIZE 5 diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_policy.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf_policy.c index c28606ca6623..848e24926ecd 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_policy.c +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_policy.c @@ -7,7 +7,6 @@ #include "abi/guc_actions_sriov_abi.h" -#include "xe_bo.h" #include "xe_gt.h" #include "xe_gt_sriov_pf_helpers.h" #include "xe_gt_sriov_pf_policy.h" diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_service.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf_service.c index 2eb21610e5a0..b5e0a5b7723e 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_service.c +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_service.c @@ -5,20 +5,19 @@ #include -#include "abi/guc_actions_sriov_abi.h" #include "abi/guc_relay_actions_abi.h" #include "regs/xe_gt_regs.h" #include "regs/xe_guc_regs.h" -#include "regs/xe_regs.h" +#include "xe_assert.h" #include "xe_mmio.h" #include "xe_gt_sriov_printk.h" -#include "xe_gt_sriov_pf_helpers.h" #include "xe_gt_sriov_pf_service.h" #include "xe_gt_sriov_pf_service_types.h" #include "xe_guc_ct.h" #include "xe_guc_hxg_helpers.h" +#include "xe_sriov.h" #include "xe_sriov_pf_service.h" static const struct xe_reg tgl_runtime_regs[] = { diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_vf.c b/drivers/gpu/drm/xe/xe_gt_sriov_vf.c index d91c65dc3496..30e8c2cf5f09 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_vf.c +++ b/drivers/gpu/drm/xe/xe_gt_sriov_vf.c @@ -15,7 +15,6 @@ #include "abi/guc_klvs_abi.h" #include "abi/guc_relay_actions_abi.h" #include "regs/xe_gt_regs.h" -#include "regs/xe_gtt_defs.h" #include "xe_assert.h" #include "xe_device.h" diff --git a/drivers/gpu/drm/xe/xe_gt_stats.c b/drivers/gpu/drm/xe/xe_gt_stats.c index 8294bcd40310..37506434d7a3 100644 --- a/drivers/gpu/drm/xe/xe_gt_stats.c +++ b/drivers/gpu/drm/xe/xe_gt_stats.c @@ -7,8 +7,8 @@ #include -#include "xe_gt.h" #include "xe_gt_stats.h" +#include "xe_gt_types.h" /** * xe_gt_stats_incr - Increments the specified stats counter diff --git a/drivers/gpu/drm/xe/xe_gt_sysfs.c b/drivers/gpu/drm/xe/xe_gt_sysfs.c index ec2b8246204b..1448be047b4a 100644 --- a/drivers/gpu/drm/xe/xe_gt_sysfs.c +++ b/drivers/gpu/drm/xe/xe_gt_sysfs.c @@ -10,7 +10,7 @@ #include -#include "xe_gt.h" +#include "xe_gt_types.h" static void xe_gt_sysfs_kobj_release(struct kobject *kobj) { diff --git a/drivers/gpu/drm/xe/xe_gt_throttle.c b/drivers/gpu/drm/xe/xe_gt_throttle.c index 570358310e97..1e7e3a31aa69 100644 --- a/drivers/gpu/drm/xe/xe_gt_throttle.c +++ b/drivers/gpu/drm/xe/xe_gt_throttle.c @@ -6,7 +6,7 @@ #include #include -#include "xe_device.h" +#include "xe_device_types.h" #include "xe_gt.h" #include "xe_gt_sysfs.h" #include "xe_gt_throttle.h" diff --git a/drivers/gpu/drm/xe/xe_guc_ads.c b/drivers/gpu/drm/xe/xe_guc_ads.c index 7e1cb6093de7..f4cbc030f4c8 100644 --- a/drivers/gpu/drm/xe/xe_guc_ads.c +++ b/drivers/gpu/drm/xe/xe_guc_ads.c @@ -28,8 +28,6 @@ #include "xe_lrc.h" #include "xe_map.h" #include "xe_mmio.h" -#include "xe_platform_types.h" -#include "xe_uc_fw.h" #include "xe_wa.h" /* Slack of a few additional entries per engine */ diff --git a/drivers/gpu/drm/xe/xe_guc_buf.c b/drivers/gpu/drm/xe/xe_guc_buf.c index c36fc31e0438..11f77decd8d1 100644 --- a/drivers/gpu/drm/xe/xe_guc_buf.c +++ b/drivers/gpu/drm/xe/xe_guc_buf.c @@ -6,7 +6,6 @@ #include #include -#include "xe_assert.h" #include "xe_bo.h" #include "xe_gt_printk.h" #include "xe_guc.h" diff --git a/drivers/gpu/drm/xe/xe_guc_capture.c b/drivers/gpu/drm/xe/xe_guc_capture.c index bdd700ac1e54..2f5816c78fba 100644 --- a/drivers/gpu/drm/xe/xe_guc_capture.c +++ b/drivers/gpu/drm/xe/xe_guc_capture.c @@ -13,17 +13,14 @@ #include "abi/guc_log_abi.h" #include "regs/xe_engine_regs.h" #include "regs/xe_gt_regs.h" -#include "regs/xe_guc_regs.h" -#include "regs/xe_regs.h" -#include "xe_bo.h" +#include "xe_bo_types.h" #include "xe_device.h" #include "xe_exec_queue_types.h" #include "xe_gt.h" #include "xe_gt_mcr.h" #include "xe_gt_printk.h" #include "xe_guc.h" -#include "xe_guc_ads.h" #include "xe_guc_capture.h" #include "xe_guc_capture_types.h" #include "xe_guc_ct.h" diff --git a/drivers/gpu/drm/xe/xe_guc_debugfs.c b/drivers/gpu/drm/xe/xe_guc_debugfs.c index 23827e87450f..2f23119686d4 100644 --- a/drivers/gpu/drm/xe/xe_guc_debugfs.c +++ b/drivers/gpu/drm/xe/xe_guc_debugfs.c @@ -8,13 +8,12 @@ #include #include -#include "xe_device.h" -#include "xe_gt.h" +#include "xe_device_types.h" +#include "xe_gt_types.h" #include "xe_guc.h" #include "xe_guc_ct.h" #include "xe_guc_log.h" #include "xe_guc_pc.h" -#include "xe_macros.h" #include "xe_pm.h" /* diff --git a/drivers/gpu/drm/xe/xe_guc_hwconfig.c b/drivers/gpu/drm/xe/xe_guc_hwconfig.c index af2c817d552c..b300901dbb8e 100644 --- a/drivers/gpu/drm/xe/xe_guc_hwconfig.c +++ b/drivers/gpu/drm/xe/xe_guc_hwconfig.c @@ -10,8 +10,8 @@ #include "abi/guc_actions_abi.h" #include "xe_bo.h" -#include "xe_device.h" -#include "xe_gt.h" +#include "xe_device_types.h" +#include "xe_gt_types.h" #include "xe_guc.h" #include "xe_map.h" diff --git a/drivers/gpu/drm/xe/xe_guc_log.c b/drivers/gpu/drm/xe/xe_guc_log.c index d7473b9673bb..acac66a4eca7 100644 --- a/drivers/gpu/drm/xe/xe_guc_log.c +++ b/drivers/gpu/drm/xe/xe_guc_log.c @@ -15,8 +15,8 @@ #include "xe_bo.h" #include "xe_devcoredump.h" #include "xe_force_wake.h" -#include "xe_gt.h" #include "xe_gt_printk.h" +#include "xe_gt_types.h" #include "xe_map.h" #include "xe_mmio.h" #include "xe_module.h" diff --git a/drivers/gpu/drm/xe/xe_guc_relay.c b/drivers/gpu/drm/xe/xe_guc_relay.c index 0c0ff24ba62a..577a315854af 100644 --- a/drivers/gpu/drm/xe/xe_guc_relay.c +++ b/drivers/gpu/drm/xe/xe_guc_relay.c @@ -17,8 +17,7 @@ #include "abi/guc_relay_communication_abi.h" #include "xe_assert.h" -#include "xe_device.h" -#include "xe_gt.h" +#include "xe_device_types.h" #include "xe_gt_sriov_printk.h" #include "xe_gt_sriov_pf_service.h" #include "xe_guc.h" diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index be8fa76baf1d..a27ea931b956 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -17,7 +17,6 @@ #include "abi/guc_actions_abi.h" #include "abi/guc_actions_slpc_abi.h" #include "abi/guc_klvs_abi.h" -#include "regs/xe_lrc_layout.h" #include "xe_assert.h" #include "xe_bo.h" #include "xe_devcoredump.h" @@ -36,7 +35,6 @@ #include "xe_guc_klv_helpers.h" #include "xe_guc_submit_types.h" #include "xe_hw_engine.h" -#include "xe_hw_fence.h" #include "xe_lrc.h" #include "xe_macros.h" #include "xe_map.h" diff --git a/drivers/gpu/drm/xe/xe_heci_gsc.c b/drivers/gpu/drm/xe/xe_heci_gsc.c index 495cdd4f948d..c1f15313f92e 100644 --- a/drivers/gpu/drm/xe/xe_heci_gsc.c +++ b/drivers/gpu/drm/xe/xe_heci_gsc.c @@ -11,7 +11,6 @@ #include #include "xe_device_types.h" -#include "xe_drv.h" #include "xe_heci_gsc.h" #include "regs/xe_gsc_regs.h" #include "xe_platform_types.h" diff --git a/drivers/gpu/drm/xe/xe_huc.c b/drivers/gpu/drm/xe/xe_huc.c index 4212162913af..57afe21444b1 100644 --- a/drivers/gpu/drm/xe/xe_huc.c +++ b/drivers/gpu/drm/xe/xe_huc.c @@ -12,7 +12,6 @@ #include "abi/gsc_pxp_commands_abi.h" #include "regs/xe_gsc_regs.h" #include "regs/xe_guc_regs.h" -#include "xe_assert.h" #include "xe_bo.h" #include "xe_device.h" #include "xe_force_wake.h" diff --git a/drivers/gpu/drm/xe/xe_huc_debugfs.c b/drivers/gpu/drm/xe/xe_huc_debugfs.c index df9c4d79b710..80829967b3d7 100644 --- a/drivers/gpu/drm/xe/xe_huc_debugfs.c +++ b/drivers/gpu/drm/xe/xe_huc_debugfs.c @@ -7,11 +7,10 @@ #include #include +#include -#include "xe_device.h" -#include "xe_gt.h" +#include "xe_gt_types.h" #include "xe_huc.h" -#include "xe_macros.h" #include "xe_pm.h" static struct xe_gt * diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c index 6a9e2a4272dd..4d3ee5226e3a 100644 --- a/drivers/gpu/drm/xe/xe_hw_engine.c +++ b/drivers/gpu/drm/xe/xe_hw_engine.c @@ -33,7 +33,6 @@ #include "xe_hw_fence.h" #include "xe_irq.h" #include "xe_lrc.h" -#include "xe_macros.h" #include "xe_mmio.h" #include "xe_reg_sr.h" #include "xe_reg_whitelist.h" diff --git a/drivers/gpu/drm/xe/xe_hw_engine_class_sysfs.c b/drivers/gpu/drm/xe/xe_hw_engine_class_sysfs.c index cb45cdceef67..3c65becb39ad 100644 --- a/drivers/gpu/drm/xe/xe_hw_engine_class_sysfs.c +++ b/drivers/gpu/drm/xe/xe_hw_engine_class_sysfs.c @@ -7,7 +7,7 @@ #include #include -#include "xe_device.h" +#include "xe_device_types.h" #include "xe_gt.h" #include "xe_hw_engine_class_sysfs.h" #include "xe_pm.h" diff --git a/drivers/gpu/drm/xe/xe_hw_engine_group.c b/drivers/gpu/drm/xe/xe_hw_engine_group.c index f69a32c27458..2ef33dfbe3a2 100644 --- a/drivers/gpu/drm/xe/xe_hw_engine_group.c +++ b/drivers/gpu/drm/xe/xe_hw_engine_group.c @@ -6,7 +6,7 @@ #include #include "xe_assert.h" -#include "xe_device.h" +#include "xe_device_types.h" #include "xe_exec_queue.h" #include "xe_gt.h" #include "xe_gt_stats.h" diff --git a/drivers/gpu/drm/xe/xe_hw_fence.c b/drivers/gpu/drm/xe/xe_hw_fence.c index 6b5bc67767d3..ae8ed15b64c5 100644 --- a/drivers/gpu/drm/xe/xe_hw_fence.c +++ b/drivers/gpu/drm/xe/xe_hw_fence.c @@ -8,9 +8,7 @@ #include #include -#include "xe_bo.h" -#include "xe_device.h" -#include "xe_gt.h" +#include "xe_device_types.h" #include "xe_hw_engine.h" #include "xe_macros.h" #include "xe_map.h" diff --git a/drivers/gpu/drm/xe/xe_i2c.c b/drivers/gpu/drm/xe/xe_i2c.c index befc77e46eae..1e1fb72e49bf 100644 --- a/drivers/gpu/drm/xe/xe_i2c.c +++ b/drivers/gpu/drm/xe/xe_i2c.c @@ -5,6 +5,7 @@ * Copyright (C) 2025 Intel Corporation. */ +#include #include #include #include @@ -26,11 +27,10 @@ #include "regs/xe_i2c_regs.h" #include "regs/xe_irq_regs.h" -#include "xe_device.h" #include "xe_device_types.h" #include "xe_i2c.h" #include "xe_mmio.h" -#include "xe_platform_types.h" +#include "xe_sriov.h" #include "xe_survivability_mode.h" /** diff --git a/drivers/gpu/drm/xe/xe_irq.c b/drivers/gpu/drm/xe/xe_irq.c index baf5d2c6e802..7560a45f7f64 100644 --- a/drivers/gpu/drm/xe/xe_irq.c +++ b/drivers/gpu/drm/xe/xe_irq.c @@ -10,7 +10,6 @@ #include #include "display/xe_display.h" -#include "regs/xe_guc_regs.h" #include "regs/xe_irq_regs.h" #include "xe_device.h" #include "xe_drv.h" diff --git a/drivers/gpu/drm/xe/xe_memirq.c b/drivers/gpu/drm/xe/xe_memirq.c index b0c7ce0a5d1e..811e07136efb 100644 --- a/drivers/gpu/drm/xe/xe_memirq.c +++ b/drivers/gpu/drm/xe/xe_memirq.c @@ -7,7 +7,6 @@ #include "regs/xe_guc_regs.h" #include "regs/xe_irq_regs.h" -#include "regs/xe_regs.h" #include "xe_assert.h" #include "xe_bo.h" @@ -16,7 +15,6 @@ #include "xe_gt.h" #include "xe_guc.h" #include "xe_hw_engine.h" -#include "xe_map.h" #include "xe_memirq.h" #include "xe_tile_printk.h" diff --git a/drivers/gpu/drm/xe/xe_mmio.c b/drivers/gpu/drm/xe/xe_mmio.c index 350dca1f0925..bcb6674b7dac 100644 --- a/drivers/gpu/drm/xe/xe_mmio.c +++ b/drivers/gpu/drm/xe/xe_mmio.c @@ -14,12 +14,8 @@ #include #include "regs/xe_bars.h" -#include "regs/xe_regs.h" #include "xe_device.h" -#include "xe_gt.h" -#include "xe_gt_printk.h" #include "xe_gt_sriov_vf.h" -#include "xe_macros.h" #include "xe_sriov.h" #include "xe_trace.h" #include "xe_wa.h" diff --git a/drivers/gpu/drm/xe/xe_mocs.c b/drivers/gpu/drm/xe/xe_mocs.c index 0b7225bd77e0..54822497c21e 100644 --- a/drivers/gpu/drm/xe/xe_mocs.c +++ b/drivers/gpu/drm/xe/xe_mocs.c @@ -6,7 +6,6 @@ #include "xe_mocs.h" #include "regs/xe_gt_regs.h" -#include "xe_bo.h" #include "xe_device.h" #include "xe_exec_queue.h" #include "xe_force_wake.h" @@ -17,7 +16,6 @@ #include "xe_platform_types.h" #include "xe_pm.h" #include "xe_sriov.h" -#include "xe_step_types.h" #if IS_ENABLED(CONFIG_DRM_XE_DEBUG) #define mocs_dbg xe_gt_dbg diff --git a/drivers/gpu/drm/xe/xe_module.c b/drivers/gpu/drm/xe/xe_module.c index 9934f90691fd..a0048f64ed12 100644 --- a/drivers/gpu/drm/xe/xe_module.c +++ b/drivers/gpu/drm/xe/xe_module.c @@ -10,7 +10,7 @@ #include -#include "xe_device.h" +#include "xe_device_types.h" #include "xe_drv.h" #include "xe_configfs.h" #include "xe_hw_fence.h" diff --git a/drivers/gpu/drm/xe/xe_nvm.c b/drivers/gpu/drm/xe/xe_nvm.c index 01510061d4d4..437375046517 100644 --- a/drivers/gpu/drm/xe/xe_nvm.c +++ b/drivers/gpu/drm/xe/xe_nvm.c @@ -6,7 +6,6 @@ #include #include -#include "xe_device.h" #include "xe_device_types.h" #include "xe_mmio.h" #include "xe_nvm.h" diff --git a/drivers/gpu/drm/xe/xe_page_reclaim.c b/drivers/gpu/drm/xe/xe_page_reclaim.c index a8f35919a9da..e13c71a89da2 100644 --- a/drivers/gpu/drm/xe/xe_page_reclaim.c +++ b/drivers/gpu/drm/xe/xe_page_reclaim.c @@ -10,15 +10,11 @@ #include "xe_page_reclaim.h" -#include "regs/xe_gt_regs.h" -#include "xe_assert.h" #include "xe_gt_stats.h" #include "xe_macros.h" -#include "xe_mmio.h" #include "xe_pat.h" #include "xe_sa.h" #include "xe_tlb_inval_types.h" -#include "xe_vm.h" /** * xe_page_reclaim_skip() - Decide whether PRL should be skipped for a VMA diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index fa0a374d88f8..09189ff3da44 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -24,7 +24,6 @@ #include "xe_gt.h" #include "xe_gt_sriov_vf.h" #include "xe_guc.h" -#include "xe_macros.h" #include "xe_mmio.h" #include "xe_module.h" #include "xe_pci_rebar.h" diff --git a/drivers/gpu/drm/xe/xe_psmi.c b/drivers/gpu/drm/xe/xe_psmi.c index 6a54e38b81ba..899b01f72ba3 100644 --- a/drivers/gpu/drm/xe/xe_psmi.c +++ b/drivers/gpu/drm/xe/xe_psmi.c @@ -6,7 +6,7 @@ #include #include "xe_bo.h" -#include "xe_device.h" +#include "xe_device_types.h" #include "xe_configfs.h" #include "xe_psmi.h" diff --git a/drivers/gpu/drm/xe/xe_pxp.c b/drivers/gpu/drm/xe/xe_pxp.c index 508f4c128a48..d61446bf9c19 100644 --- a/drivers/gpu/drm/xe/xe_pxp.c +++ b/drivers/gpu/drm/xe/xe_pxp.c @@ -15,7 +15,6 @@ #include "xe_force_wake.h" #include "xe_guc_submit.h" #include "xe_gsc_proxy.h" -#include "xe_gt.h" #include "xe_gt_types.h" #include "xe_huc.h" #include "xe_mmio.h" diff --git a/drivers/gpu/drm/xe/xe_pxp_debugfs.c b/drivers/gpu/drm/xe/xe_pxp_debugfs.c index 525a2f6bb076..d6e2e41bc88c 100644 --- a/drivers/gpu/drm/xe/xe_pxp_debugfs.c +++ b/drivers/gpu/drm/xe/xe_pxp_debugfs.c @@ -11,7 +11,7 @@ #include #include -#include "xe_device.h" +#include "xe_device_types.h" #include "xe_pxp.h" #include "xe_pxp_types.h" #include "regs/xe_irq_regs.h" diff --git a/drivers/gpu/drm/xe/xe_reg_sr.c b/drivers/gpu/drm/xe/xe_reg_sr.c index 1a465385f909..d3e13ea33123 100644 --- a/drivers/gpu/drm/xe/xe_reg_sr.c +++ b/drivers/gpu/drm/xe/xe_reg_sr.c @@ -13,16 +13,13 @@ #include #include -#include "regs/xe_engine_regs.h" -#include "regs/xe_gt_regs.h" #include "xe_device.h" #include "xe_device_types.h" #include "xe_force_wake.h" -#include "xe_gt.h" #include "xe_gt_mcr.h" #include "xe_gt_printk.h" +#include "xe_gt_types.h" #include "xe_hw_engine_types.h" -#include "xe_macros.h" #include "xe_mmio.h" #include "xe_rtp_types.h" diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.c b/drivers/gpu/drm/xe/xe_reg_whitelist.c index 1391cb6ec9c6..1d36c09681aa 100644 --- a/drivers/gpu/drm/xe/xe_reg_whitelist.c +++ b/drivers/gpu/drm/xe/xe_reg_whitelist.c @@ -8,7 +8,6 @@ #include "regs/xe_engine_regs.h" #include "regs/xe_gt_regs.h" #include "regs/xe_oa_regs.h" -#include "regs/xe_regs.h" #include "xe_device.h" #include "xe_gt_types.h" #include "xe_gt_printk.h" diff --git a/drivers/gpu/drm/xe/xe_ring_ops.c b/drivers/gpu/drm/xe/xe_ring_ops.c index a1fd99f2d539..248620b0901d 100644 --- a/drivers/gpu/drm/xe/xe_ring_ops.c +++ b/drivers/gpu/drm/xe/xe_ring_ops.c @@ -11,11 +11,9 @@ #include "instructions/xe_mi_commands.h" #include "regs/xe_engine_regs.h" #include "regs/xe_gt_regs.h" -#include "regs/xe_lrc_layout.h" #include "xe_exec_queue.h" -#include "xe_gt.h" +#include "xe_gt_types.h" #include "xe_lrc.h" -#include "xe_macros.h" #include "xe_sched_job.h" #include "xe_sriov.h" #include "xe_vm_types.h" diff --git a/drivers/gpu/drm/xe/xe_rtp.c b/drivers/gpu/drm/xe/xe_rtp.c index ed509b1c8cfc..b7c26e2fb411 100644 --- a/drivers/gpu/drm/xe/xe_rtp.c +++ b/drivers/gpu/drm/xe/xe_rtp.c @@ -12,7 +12,6 @@ #include "xe_configfs.h" #include "xe_gt.h" #include "xe_gt_topology.h" -#include "xe_macros.h" #include "xe_reg_sr.h" #include "xe_sriov.h" diff --git a/drivers/gpu/drm/xe/xe_sa.c b/drivers/gpu/drm/xe/xe_sa.c index a87c1436c7c1..b738102575d4 100644 --- a/drivers/gpu/drm/xe/xe_sa.c +++ b/drivers/gpu/drm/xe/xe_sa.c @@ -10,7 +10,7 @@ #include #include "xe_bo.h" -#include "xe_device.h" +#include "xe_device_types.h" #include "xe_map.h" static void xe_sa_bo_manager_fini(struct drm_device *drm, void *arg) diff --git a/drivers/gpu/drm/xe/xe_sched_job.c b/drivers/gpu/drm/xe/xe_sched_job.c index 39aec7f6d86d..3927666fe556 100644 --- a/drivers/gpu/drm/xe/xe_sched_job.c +++ b/drivers/gpu/drm/xe/xe_sched_job.c @@ -11,7 +11,7 @@ #include "xe_device.h" #include "xe_exec_queue.h" -#include "xe_gt.h" +#include "xe_gt_types.h" #include "xe_hw_engine_types.h" #include "xe_hw_fence.h" #include "xe_lrc.h" diff --git a/drivers/gpu/drm/xe/xe_sriov_packet.c b/drivers/gpu/drm/xe/xe_sriov_packet.c index 2cefefaed9ba..7a4c3de662e5 100644 --- a/drivers/gpu/drm/xe/xe_sriov_packet.c +++ b/drivers/gpu/drm/xe/xe_sriov_packet.c @@ -6,7 +6,6 @@ #include "xe_bo.h" #include "xe_device.h" #include "xe_guc_klv_helpers.h" -#include "xe_printk.h" #include "xe_sriov_packet.h" #include "xe_sriov_packet_types.h" #include "xe_sriov_pf_helpers.h" diff --git a/drivers/gpu/drm/xe/xe_sriov_pf_debugfs.c b/drivers/gpu/drm/xe/xe_sriov_pf_debugfs.c index e84bdde9bc80..81b377830d6d 100644 --- a/drivers/gpu/drm/xe/xe_sriov_pf_debugfs.c +++ b/drivers/gpu/drm/xe/xe_sriov_pf_debugfs.c @@ -16,7 +16,6 @@ #include "xe_sriov_pf_migration.h" #include "xe_sriov_pf_provision.h" #include "xe_sriov_pf_service.h" -#include "xe_sriov_printk.h" #include "xe_tile_sriov_pf_debugfs.h" /* diff --git a/drivers/gpu/drm/xe/xe_sriov_vf.c b/drivers/gpu/drm/xe/xe_sriov_vf.c index 1b75405b8d02..29894bd081c0 100644 --- a/drivers/gpu/drm/xe/xe_sriov_vf.c +++ b/drivers/gpu/drm/xe/xe_sriov_vf.c @@ -6,7 +6,6 @@ #include #include -#include "xe_gt.h" #include "xe_gt_sriov_vf.h" #include "xe_guc.h" #include "xe_sriov_printk.h" diff --git a/drivers/gpu/drm/xe/xe_step.c b/drivers/gpu/drm/xe/xe_step.c index 10e88f2c9615..2860986f82f7 100644 --- a/drivers/gpu/drm/xe/xe_step.c +++ b/drivers/gpu/drm/xe/xe_step.c @@ -5,10 +5,11 @@ #include "xe_step.h" +#include #include #include -#include "xe_device.h" +#include "xe_device_types.h" #include "xe_platform_types.h" /* diff --git a/drivers/gpu/drm/xe/xe_survivability_mode.c b/drivers/gpu/drm/xe/xe_survivability_mode.c index 31456f432fc8..6578ffc77bd5 100644 --- a/drivers/gpu/drm/xe/xe_survivability_mode.c +++ b/drivers/gpu/drm/xe/xe_survivability_mode.c @@ -12,7 +12,6 @@ #include "xe_configfs.h" #include "xe_device.h" -#include "xe_gt.h" #include "xe_heci_gsc.h" #include "xe_i2c.h" #include "xe_mmio.h" diff --git a/drivers/gpu/drm/xe/xe_tile.c b/drivers/gpu/drm/xe/xe_tile.c index eb262aad11da..c465aae7883c 100644 --- a/drivers/gpu/drm/xe/xe_tile.c +++ b/drivers/gpu/drm/xe/xe_tile.c @@ -9,9 +9,8 @@ #include #include "xe_bo.h" -#include "xe_device.h" +#include "xe_device_types.h" #include "xe_ggtt.h" -#include "xe_gt.h" #include "xe_memirq.h" #include "xe_migrate.h" #include "xe_pcode.h" diff --git a/drivers/gpu/drm/xe/xe_tlb_inval.c b/drivers/gpu/drm/xe/xe_tlb_inval.c index 61b99cf0a733..e837888367c4 100644 --- a/drivers/gpu/drm/xe/xe_tlb_inval.c +++ b/drivers/gpu/drm/xe/xe_tlb_inval.c @@ -5,13 +5,10 @@ #include -#include "abi/guc_actions_abi.h" -#include "xe_device.h" +#include "xe_device_types.h" #include "xe_force_wake.h" -#include "xe_gt.h" -#include "xe_gt_printk.h" #include "xe_gt_stats.h" -#include "xe_guc.h" +#include "xe_gt_types.h" #include "xe_guc_ct.h" #include "xe_guc_tlb_inval.h" #include "xe_mmio.h" diff --git a/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c b/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c index 1bddecfb723a..27c9d72222cf 100644 --- a/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c +++ b/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c @@ -17,7 +17,6 @@ #include "regs/xe_regs.h" #include "xe_bo.h" #include "xe_device.h" -#include "xe_gt.h" #include "xe_gt_printk.h" #include "xe_mmio.h" #include "xe_res_cursor.h" diff --git a/drivers/gpu/drm/xe/xe_ttm_sys_mgr.c b/drivers/gpu/drm/xe/xe_ttm_sys_mgr.c index 3e404eb8d098..99fb7e99eb7f 100644 --- a/drivers/gpu/drm/xe/xe_ttm_sys_mgr.c +++ b/drivers/gpu/drm/xe/xe_ttm_sys_mgr.c @@ -13,7 +13,6 @@ #include #include "xe_bo.h" -#include "xe_gt.h" struct xe_ttm_sys_node { struct ttm_buffer_object *tbo; diff --git a/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c b/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c index 9f70802fce92..6553a19f7cf2 100644 --- a/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c +++ b/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c @@ -12,7 +12,6 @@ #include "xe_bo.h" #include "xe_device.h" -#include "xe_gt.h" #include "xe_res_cursor.h" #include "xe_ttm_vram_mgr.h" #include "xe_vram_types.h" diff --git a/drivers/gpu/drm/xe/xe_uc.c b/drivers/gpu/drm/xe/xe_uc.c index 157520ea1783..3f63c2a7e86d 100644 --- a/drivers/gpu/drm/xe/xe_uc.c +++ b/drivers/gpu/drm/xe/xe_uc.c @@ -8,7 +8,6 @@ #include "xe_assert.h" #include "xe_device.h" #include "xe_gsc.h" -#include "xe_gsc_proxy.h" #include "xe_gt.h" #include "xe_gt_printk.h" #include "xe_gt_sriov_vf.h" @@ -17,7 +16,6 @@ #include "xe_guc_engine_activity.h" #include "xe_huc.h" #include "xe_sriov.h" -#include "xe_uc_fw.h" #include "xe_wopcm.h" static struct xe_gt * diff --git a/drivers/gpu/drm/xe/xe_uc_debugfs.c b/drivers/gpu/drm/xe/xe_uc_debugfs.c index 24a4209051ee..45119993f5cb 100644 --- a/drivers/gpu/drm/xe/xe_uc_debugfs.c +++ b/drivers/gpu/drm/xe/xe_uc_debugfs.c @@ -7,12 +7,12 @@ #include -#include "xe_gt.h" #include "xe_gsc_debugfs.h" #include "xe_guc_debugfs.h" #include "xe_huc_debugfs.h" #include "xe_macros.h" #include "xe_uc_debugfs.h" +#include "xe_uc_types.h" void xe_uc_debugfs_register(struct xe_uc *uc, struct dentry *parent) { diff --git a/drivers/gpu/drm/xe/xe_uc_fw.c b/drivers/gpu/drm/xe/xe_uc_fw.c index f5788db5073c..d35bc4989144 100644 --- a/drivers/gpu/drm/xe/xe_uc_fw.c +++ b/drivers/gpu/drm/xe/xe_uc_fw.c @@ -14,9 +14,9 @@ #include "xe_device_types.h" #include "xe_force_wake.h" #include "xe_gsc.h" -#include "xe_gt.h" #include "xe_gt_printk.h" #include "xe_gt_sriov_vf.h" +#include "xe_gt_types.h" #include "xe_guc.h" #include "xe_map.h" #include "xe_mmio.h" diff --git a/drivers/gpu/drm/xe/xe_validation.c b/drivers/gpu/drm/xe/xe_validation.c index 826cd09966ef..a611438eaafe 100644 --- a/drivers/gpu/drm/xe/xe_validation.c +++ b/drivers/gpu/drm/xe/xe_validation.c @@ -2,7 +2,6 @@ /* * Copyright © 2024 Intel Corporation */ -#include "xe_bo.h" #include #include #include diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index 001bc36da5ef..bbbc7e71b8ef 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -33,7 +33,6 @@ #include "xe_preempt_fence.h" #include "xe_pt.h" #include "xe_pxp.h" -#include "xe_res_cursor.h" #include "xe_sriov_vf.h" #include "xe_svm.h" #include "xe_sync.h" diff --git a/drivers/gpu/drm/xe/xe_vram.c b/drivers/gpu/drm/xe/xe_vram.c index 4f807eade2b7..0538dcb8b18c 100644 --- a/drivers/gpu/drm/xe/xe_vram.c +++ b/drivers/gpu/drm/xe/xe_vram.c @@ -13,12 +13,10 @@ #include "regs/xe_gt_regs.h" #include "regs/xe_regs.h" #include "xe_assert.h" -#include "xe_bo.h" #include "xe_device.h" #include "xe_force_wake.h" #include "xe_gt_mcr.h" #include "xe_mmio.h" -#include "xe_module.h" #include "xe_sriov.h" #include "xe_tile_sriov_vf.h" #include "xe_ttm_vram_mgr.h" diff --git a/drivers/gpu/drm/xe/xe_vram_freq.c b/drivers/gpu/drm/xe/xe_vram_freq.c index 17bc84da4cdc..6f8281e0b96a 100644 --- a/drivers/gpu/drm/xe/xe_vram_freq.c +++ b/drivers/gpu/drm/xe/xe_vram_freq.c @@ -5,7 +5,6 @@ #include #include -#include "xe_gt_types.h" #include "xe_pcode.h" #include "xe_pcode_api.h" #include "xe_tile.h" diff --git a/drivers/gpu/drm/xe/xe_vsec.c b/drivers/gpu/drm/xe/xe_vsec.c index c83ea3d48fae..4ebb4dbe1c9b 100644 --- a/drivers/gpu/drm/xe/xe_vsec.c +++ b/drivers/gpu/drm/xe/xe_vsec.c @@ -12,7 +12,6 @@ #include "xe_device.h" #include "xe_device_types.h" -#include "xe_drv.h" #include "xe_mmio.h" #include "xe_platform_types.h" #include "xe_pm.h" diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c index a93717e77da0..a991ee2b8781 100644 --- a/drivers/gpu/drm/xe/xe_wa.c +++ b/drivers/gpu/drm/xe/xe_wa.c @@ -19,7 +19,7 @@ #include "regs/xe_regs.h" #include "xe_device_types.h" #include "xe_force_wake.h" -#include "xe_gt.h" +#include "xe_gt_types.h" #include "xe_hw_engine_types.h" #include "xe_mmio.h" #include "xe_platform_types.h" diff --git a/drivers/gpu/drm/xe/xe_wait_user_fence.c b/drivers/gpu/drm/xe/xe_wait_user_fence.c index 5b4264ea38bd..51eb940ceb4e 100644 --- a/drivers/gpu/drm/xe/xe_wait_user_fence.c +++ b/drivers/gpu/drm/xe/xe_wait_user_fence.c @@ -11,7 +11,6 @@ #include #include "xe_device.h" -#include "xe_gt.h" #include "xe_macros.h" #include "xe_exec_queue.h" diff --git a/drivers/gpu/drm/xe/xe_wopcm.c b/drivers/gpu/drm/xe/xe_wopcm.c index ada0d0aa6b74..dde4f4967ca3 100644 --- a/drivers/gpu/drm/xe/xe_wopcm.c +++ b/drivers/gpu/drm/xe/xe_wopcm.c @@ -10,7 +10,7 @@ #include "regs/xe_guc_regs.h" #include "xe_device.h" #include "xe_force_wake.h" -#include "xe_gt.h" +#include "xe_gt_types.h" #include "xe_mmio.h" #include "xe_uc_fw.h" -- cgit v1.2.3