[PATCH v2] drm/amdgpu: skip BOs being torn down during GTT recovery

Yifan Zhang <[email protected]> Thu, 30 Jul 2026 14:43:50 +0800
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <[email protected]>
A GPU reset can race with BO teardown after the BO's GTT resource has
been marked for deletion but before its drm_mm node is removed. In this
window, amdgpu_gtt_mgr_recover() can treat the node as a live BO and try
to restore its GART mapping while its TT backing is being destroyed.

Mark the GTT node with a dedicated stale-BO color from
amdgpu_bo_delete_mem_notify(). During recovery, process only nodes
colored as live BOs, leaving both stale-BO nodes and nodes without a BO
untouched.

This prevents reset recovery from accessing a BO whose backing storage
is no longer valid.

amdgpu 0000:a3:00.0: GPU reset succeeded, trying to resume
BUG: kernel NULL pointer dereference, address: 0000000000000000
PGD 62256dd067 P4D 0
Oops: Oops: 0000 [#1] SMP NOPTI
Workqueue: amdgpu-reset-dev amdgpu_debugfs_reset_work [amdgpu]
Call Trace:
 <TASK>
 amdgpu_gart_bind+0x1a/0x50 [amdgpu]
 amdgpu_ttm_gart_bind+0xd8/0xe0 [amdgpu]
 amdgpu_ttm_recover_gart+0x5f/0x80 [amdgpu]
 amdgpu_gtt_mgr_recover+0x43/0x70 [amdgpu]
 gmc_v12_0_hw_init+0x46/0x160 [amdgpu]
 gmc_v12_0_resume+0x14/0x40 [amdgpu]
 amdgpu_ip_block_resume+0x24/0x80 [amdgpu]
 amdgpu_device_ip_resume_phase1+0xce/0x180 [amdgpu]
 amdgpu_device_reinit_after_reset+0x13d/0x340 [amdgpu]
 amdgpu_do_asic_reset.part.0+0x56/0x1b0 [amdgpu]
 amdgpu_device_asic_reset+0x426/0x640 [amdgpu]
 ? srso_alias_return_thunk+0x5/0xfbef5
 amdgpu_device_gpu_recover+0x260/0x410 [amdgpu]
 amdgpu_debugfs_reset_work+0x68/0x90 [amdgpu]
 process_one_work+0x18e/0x3e0
 worker_thread+0x2e3/0x420
 ? _raw_spin_lock_irqsave+0xe/0x20
 ? srso_alias_return_thunk+0x5/0xfbef5
 ? __pfx_worker_thread+0x10/0x10
 kthread+0x10a/0x230
 ? __pfx_kthread+0x10/0x10
 ret_from_fork+0x121/0x140
 ? __pfx_kthread+0x10/0x10
 ret_from_fork_asm+0x1a/0x30
 </TASK>

Signed-off-by: Yifan Zhang <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c | 44 +++++++++++++++++++--
 drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c     |  1 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h     |  1 +
 3 files changed, 42 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
index 0ea32561c4bc..93d564bbad76 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
@@ -26,7 +26,13 @@
 
 #include "amdgpu.h"
 
-#define GART_ENTRY_WITHOUT_BO_COLOR	1
+/*
+ * drm_mm node colors describing what a GART range belongs to:
+ * a usable GTT BO, no BO at all, or a GTT BO whose TT backing is going away.
+ */
+#define GART_ENTRY_COLOR_LIVE_BO	0
+#define GART_ENTRY_COLOR_NO_BO		1
+#define GART_ENTRY_COLOR_STALE_BO	2
 
 static inline struct amdgpu_gtt_mgr *
 to_gtt_mgr(struct ttm_resource_manager *man)
@@ -102,6 +108,35 @@ bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *res)
 	return drm_mm_node_allocated(&node->mm_nodes[0]);
 }
 
+/**
+ * amdgpu_gtt_mgr_mark_bo_teardown - exclude a BO from GART recovery
+ *
+ * @tbo: TTM BO whose TT backing is about to be destroyed
+ *
+ * Keep the GART range allocated until the resource is freed, but prevent
+ * reset recovery from using the BO after TT teardown has started.
+ */
+void amdgpu_gtt_mgr_mark_bo_teardown(struct ttm_buffer_object *tbo)
+{
+	struct amdgpu_device *adev = amdgpu_ttm_adev(tbo->bdev);
+	struct ttm_resource *res = tbo->resource;
+	struct ttm_range_mgr_node *node;
+	struct amdgpu_gtt_mgr *mgr;
+
+	dma_resv_assert_held(tbo->base.resv);
+
+	if (!res || res->mem_type != TTM_PL_TT)
+		return;
+
+	node = to_ttm_range_mgr_node(res);
+	mgr = &adev->mman.gtt_mgr;
+
+	spin_lock(&mgr->lock);
+	if (drm_mm_node_allocated(&node->mm_nodes[0]))
+		node->mm_nodes[0].color = GART_ENTRY_COLOR_STALE_BO;
+	spin_unlock(&mgr->lock);
+}
+
 /**
  * amdgpu_gtt_mgr_new - allocate a new node
  *
@@ -137,7 +172,8 @@ static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man,
 		spin_lock(&mgr->lock);
 		r = drm_mm_insert_node_in_range(&mgr->mm, &node->mm_nodes[0],
 						num_pages, tbo->page_alignment,
-						0, place->fpfn, place->lpfn,
+						GART_ENTRY_COLOR_LIVE_BO,
+						place->fpfn, place->lpfn,
 						DRM_MM_INSERT_BEST);
 		spin_unlock(&mgr->lock);
 		if (unlikely(r))
@@ -210,7 +246,7 @@ int amdgpu_gtt_mgr_alloc_entries(struct amdgpu_gtt_mgr *mgr,
 
 	spin_lock(&mgr->lock);
 	r = drm_mm_insert_node_in_range(&mgr->mm, mm_node, num_pages,
-					alignment, GART_ENTRY_WITHOUT_BO_COLOR, 0,
+					alignment, GART_ENTRY_COLOR_NO_BO, 0,
 					adev->gmc.gart_size >> PAGE_SHIFT,
 					mode);
 	spin_unlock(&mgr->lock);
@@ -248,7 +284,7 @@ void amdgpu_gtt_mgr_recover(struct amdgpu_gtt_mgr *mgr)
 	adev = container_of(mgr, typeof(*adev), mman.gtt_mgr);
 	spin_lock(&mgr->lock);
 	drm_mm_for_each_node(mm_node, &mgr->mm) {
-		if (mm_node->color == GART_ENTRY_WITHOUT_BO_COLOR)
+		if (mm_node->color != GART_ENTRY_COLOR_LIVE_BO)
 			continue;
 
 		node = container_of(mm_node, typeof(*node), mm_nodes[0]);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index c4094edbdff1..ab4c2c78f639 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -1694,6 +1694,7 @@ static int amdgpu_ttm_access_memory(struct ttm_buffer_object *bo,
 static void
 amdgpu_bo_delete_mem_notify(struct ttm_buffer_object *bo)
 {
+	amdgpu_gtt_mgr_mark_bo_teardown(bo);
 	amdgpu_bo_move_notify(bo, false, NULL);
 }
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
index ff9e2e346609..af1e7fcc7175 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
@@ -145,6 +145,7 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev);
 void amdgpu_vram_mgr_fini(struct amdgpu_device *adev);
 
 bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *mem);
+void amdgpu_gtt_mgr_mark_bo_teardown(struct ttm_buffer_object *tbo);
 void amdgpu_gtt_mgr_recover(struct amdgpu_gtt_mgr *mgr);
 
 int amdgpu_gtt_mgr_alloc_entries(struct amdgpu_gtt_mgr *mgr,
-- 
2.43.0