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

Reply via email to