GGTT node removal can clear entries and invalidate TLBs after wedge isolation or after AER disables the PCI device.
Check the wedge state inside drm_dev_enter()/drm_dev_exit() so isolation can drain hardware cleanup admitted before the wedge. Software node removal and drm_mm bookkeeping still run when hardware access is skipped. For AER, take the old GGTT offline under ggtt->lock before draining readers and disabling PCI. Node removal checks the online state under the same lock, so later removals skip hardware access. Re-probe creates a new online GGTT and preserves cleanup on the recovered instance. v3: - Take the old GGTT offline before AER drains readers and disables PCI. - Preserve GGTT cleanup on the recovered instance. Cc: Matthew Brost <[email protected]> Cc: Thomas Hellström <[email protected]> Cc: Himal Prasad Ghimiray <[email protected]> Cc: Rodrigo Vivi <[email protected]> Assisted-by: LLM Signed-off-by: Arvind Yadav <[email protected]> --- drivers/gpu/drm/xe/xe_ggtt.c | 43 ++++++++++++++++++++++++++++--- drivers/gpu/drm/xe/xe_ggtt.h | 1 + drivers/gpu/drm/xe/xe_pci_error.c | 8 ++++++ 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_ggtt.c b/drivers/gpu/drm/xe/xe_ggtt.c index 773777afc68a..6fec8a90e4cf 100644 --- a/drivers/gpu/drm/xe/xe_ggtt.c +++ b/drivers/gpu/drm/xe/xe_ggtt.c @@ -20,6 +20,7 @@ #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" @@ -370,12 +371,25 @@ int xe_ggtt_init_kunit(struct xe_ggtt *ggtt, u32 start, u32 size) } EXPORT_SYMBOL_IF_KUNIT(xe_ggtt_init_kunit); +/** + * xe_ggtt_offline - Stop hardware access from GGTT node removal + * @ggtt: the &xe_ggtt to take offline + * + * Node removal keeps clearing entries and invalidating TLBs while the GGTT + * is online. Take it offline before disabling PCI access, and drain the DRM + * device SRCU afterwards so users already admitted finish first. + */ +void xe_ggtt_offline(struct xe_ggtt *ggtt) +{ + guard(mutex)(&ggtt->lock); + ggtt->flags &= ~XE_GGTT_FLAGS_ONLINE; +} + static void dev_fini_ggtt(void *arg) { struct xe_ggtt *ggtt = arg; - scoped_guard(mutex, &ggtt->lock) - ggtt->flags &= ~XE_GGTT_FLAGS_ONLINE; + xe_ggtt_offline(ggtt); drain_workqueue(ggtt->wq); } @@ -475,13 +489,13 @@ static void ggtt_node_fini(struct xe_ggtt_node *node) kfree(node); } -static void ggtt_node_remove(struct xe_ggtt_node *node) +static void __ggtt_node_remove(struct xe_ggtt_node *node, bool clear_hw) { struct xe_ggtt *ggtt = node->ggtt; bool bound; mutex_lock(&ggtt->lock); - bound = ggtt->flags & XE_GGTT_FLAGS_ONLINE; + bound = clear_hw && (ggtt->flags & XE_GGTT_FLAGS_ONLINE); if (bound) xe_ggtt_clear(ggtt, xe_ggtt_node_addr(node), xe_ggtt_node_size(node)); drm_mm_remove_node(&node->base); @@ -496,6 +510,27 @@ static void ggtt_node_remove(struct xe_ggtt_node *node) ggtt_node_fini(node); } +static void ggtt_node_remove(struct xe_ggtt_node *node) +{ + struct xe_device *xe = tile_to_xe(node->ggtt->tile); + int idx; + + /* + * GGTT updates write page table entries through the BAR and request a + * TLB invalidation. Skip them after unplug, where the BAR is gone. + * Keep them during PCI error recovery so a recovered device does not + * inherit stale GGTT entries. + */ + if (!drm_dev_enter(&xe->drm, &idx)) { + __ggtt_node_remove(node, false); + return; + } + + __ggtt_node_remove(node, !xe_device_wedged(xe)); + + drm_dev_exit(idx); +} + static void ggtt_node_remove_work_func(struct work_struct *work) { struct xe_ggtt_node *node = container_of(work, typeof(*node), diff --git a/drivers/gpu/drm/xe/xe_ggtt.h b/drivers/gpu/drm/xe/xe_ggtt.h index c864cc975a69..48db1a8fc58d 100644 --- a/drivers/gpu/drm/xe/xe_ggtt.h +++ b/drivers/gpu/drm/xe/xe_ggtt.h @@ -17,6 +17,7 @@ struct xe_ggtt *xe_ggtt_alloc(struct xe_tile *tile); int xe_ggtt_init_early(struct xe_ggtt *ggtt); int xe_ggtt_init_kunit(struct xe_ggtt *ggtt, u32 reserved, u32 size); int xe_ggtt_init(struct xe_ggtt *ggtt); +void xe_ggtt_offline(struct xe_ggtt *ggtt); void xe_ggtt_shift_nodes(struct xe_ggtt *ggtt, u64 new_base); u64 xe_ggtt_start(struct xe_ggtt *ggtt); diff --git a/drivers/gpu/drm/xe/xe_pci_error.c b/drivers/gpu/drm/xe/xe_pci_error.c index 3dfcef03850e..6606e2457503 100644 --- a/drivers/gpu/drm/xe/xe_pci_error.c +++ b/drivers/gpu/drm/xe/xe_pci_error.c @@ -6,17 +6,20 @@ #include <linux/pci.h> #include "xe_device.h" +#include "xe_ggtt.h" #include "xe_gt.h" #include "xe_log.h" #include "xe_pci.h" #include "xe_printk.h" #include "xe_ras.h" #include "xe_survivability_mode.h" +#include "xe_tile.h" static void prepare_device_for_reset(struct pci_dev *pdev) { struct xe_device *xe = pdev_to_xe_device(pdev); struct xe_gt *gt; + struct xe_tile *tile; u8 id; /* Block device access until PCI error recovery completes. */ @@ -26,6 +29,11 @@ static void prepare_device_for_reset(struct pci_dev *pdev) for_each_gt(gt, xe, id) xe_gt_declare_wedged(gt); + /* Stop GGTT removal MMIO before draining users and disabling PCI. */ + for_each_tile(tile, xe, id) + if (tile->mem.ggtt) + xe_ggtt_offline(tile->mem.ggtt); + /* * GT wedging signals pending fences. Existing hardware users can now * finish without blocking reset. -- 2.43.0
