* [PATCH 1/3] drm/amdgpu: unwind TTM on amdgpu_ttm_init() failure
2026-11-13 14:41 [PATCH 0/3] drm/amdgpu: fix TTM device_list use-after-free on failed probe Mario Limonciello
@ 2026-11-13 14:41 ` Mario Limonciello
2026-11-13 14:41 ` [PATCH 2/3] drm/amdgpu: unwind bo_init on GMC sw_init failure Mario Limonciello
2026-11-13 14:41 ` [PATCH 3/3] drm/amdgpu: release WC memtype and MTRR when amdgpu_bo_init() fails Mario Limonciello
2 siblings, 0 replies; 6+ messages in thread
From: Mario Limonciello @ 2026-11-13 14:41 UTC (permalink / raw)
To: Alex Deucher, Christian König; +Cc: amd-gfx, Mario Limonciello
If amdgpu_ttm_init() fails after ttm_device_init() succeeded, the error
paths just return. Nothing later calls ttm_device_fini() because the GMC
IP block never reaches sw_fini, so the freed amdgpu_device stays linked
on ttm_glob.device_list. The next ttm_device_init() or
ttm_global_swapout() then walks freed memory. The MMIO_REMAP BO created
in amdgpu_ttm_init() is also leaked, which shows up as "Memory manager
not clean" on the following bind.
Route every error after ttm_device_init() through amdgpu_ttm_fini(), and
mark the manager initialized as soon as ttm_device_init() succeeds so the
unwind also covers a pool init failure. Make amdgpu_ttm_fini() skip the
VRAM, GTT and PREEMPT managers when they were never registered, as it can
now run on a partially initialized device.
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 43 ++++++++++++++++++++-------------
1 file changed, 26 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index 8dfa92967b630..7828caf8aba0d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -2153,20 +2153,21 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
"failed initializing buffer object driver(%d).\n", r);
return r;
}
+ /* from here on amdgpu_ttm_fini() is responsible for unwinding */
+ adev->mman.initialized = true;
r = amdgpu_ttm_pools_init(adev);
if (r) {
dev_err(adev->dev, "failed to init ttm pools(%d).\n", r);
- return r;
+ goto err_fini;
}
- adev->mman.initialized = true;
if (!adev->gmc.is_app_apu) {
/* Initialize VRAM pool with all of VRAM divided into pages */
r = amdgpu_vram_mgr_init(adev);
if (r) {
dev_err(adev->dev, "Failed initializing VRAM heap.\n");
- return r;
+ goto err_fini;
}
}
@@ -2190,7 +2191,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
r = amdgpu_ttm_alloc_vram_resv_regions(adev);
if (r)
- return r;
+ goto err_fini;
/* RAS loads and reserves bad pages */
amdgpu_ras_mgr_early_init_service(adev);
@@ -2239,7 +2240,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
r = amdgpu_gtt_mgr_init(adev, gtt_size);
if (r) {
dev_err(adev->dev, "Failed initializing GTT heap.\n");
- return r;
+ goto err_fini;
}
dev_info(adev->dev, " %uM of GTT memory ready.\n",
(unsigned int)(gtt_size / (1024 * 1024)));
@@ -2253,52 +2254,52 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_DOORBELL, adev->doorbell.size / PAGE_SIZE);
if (r) {
dev_err(adev->dev, "Failed initializing doorbell heap.\n");
- return r;
+ goto err_fini;
}
/* Create a doorbell page for kernel usages */
r = amdgpu_doorbell_create_kernel_doorbells(adev);
if (r) {
dev_err(adev->dev, "Failed to initialize kernel doorbells.\n");
- return r;
+ goto err_fini;
}
/* Initialize MMIO-remap pool (single page 4K) */
r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_MMIO_REMAP, 1);
if (r) {
dev_err(adev->dev, "Failed initializing MMIO-remap heap.\n");
- return r;
+ goto err_fini;
}
/* Allocate the singleton MMIO_REMAP BO if supported */
r = amdgpu_ttm_alloc_mmio_remap_bo(adev);
if (r)
- return r;
+ goto err_fini;
/* Initialize preemptible memory pool */
r = amdgpu_preempt_mgr_init(adev);
if (r) {
dev_err(adev->dev, "Failed initializing PREEMPT heap.\n");
- return r;
+ goto err_fini;
}
/* Initialize various on-chip memory pools */
r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_GDS, adev->gds.gds_size);
if (r) {
dev_err(adev->dev, "Failed initializing GDS heap.\n");
- return r;
+ goto err_fini;
}
r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_GWS, adev->gds.gws_size);
if (r) {
dev_err(adev->dev, "Failed initializing gws heap.\n");
- return r;
+ goto err_fini;
}
r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_OA, adev->gds.oa_size);
if (r) {
dev_err(adev->dev, "Failed initializing oa heap.\n");
- return r;
+ goto err_fini;
}
if (adev->ualink.npa_size) {
@@ -2306,7 +2307,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
adev->ualink.npa_size);
if (r) {
dev_err(adev->dev, "Failed initializing NPA heap.\n");
- return r;
+ goto err_fini;
}
}
@@ -2318,6 +2319,10 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
"Debug VRAM access will use slowpath MM access\n");
return 0;
+
+err_fini:
+ amdgpu_ttm_fini(adev);
+ return r;
}
/*
@@ -2352,10 +2357,14 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev)
adev->mman.aper_base_kaddr = NULL;
}
- if (!adev->gmc.is_app_apu)
+ /* may be called on a partially initialized TTM, skip unregistered managers */
+ if (!adev->gmc.is_app_apu &&
+ ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM))
amdgpu_vram_mgr_fini(adev);
- amdgpu_gtt_mgr_fini(adev);
- amdgpu_preempt_mgr_fini(adev);
+ if (ttm_manager_type(&adev->mman.bdev, TTM_PL_TT))
+ amdgpu_gtt_mgr_fini(adev);
+ if (ttm_manager_type(&adev->mman.bdev, AMDGPU_PL_PREEMPT))
+ amdgpu_preempt_mgr_fini(adev);
amdgpu_doorbell_fini(adev);
ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_GDS);
--
2.43.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 2/3] drm/amdgpu: unwind bo_init on GMC sw_init failure
2026-11-13 14:41 [PATCH 0/3] drm/amdgpu: fix TTM device_list use-after-free on failed probe Mario Limonciello
2026-11-13 14:41 ` [PATCH 1/3] drm/amdgpu: unwind TTM on amdgpu_ttm_init() failure Mario Limonciello
@ 2026-11-13 14:41 ` Mario Limonciello
2026-11-13 14:56 ` sashiko-bot
2026-11-13 14:41 ` [PATCH 3/3] drm/amdgpu: release WC memtype and MTRR when amdgpu_bo_init() fails Mario Limonciello
2 siblings, 1 reply; 6+ messages in thread
From: Mario Limonciello @ 2026-11-13 14:41 UTC (permalink / raw)
To: Alex Deucher, Christian König; +Cc: amd-gfx, Mario Limonciello
When gmc_v*_sw_init() fails after amdgpu_bo_init(), the GMC block's
status.sw stays false, so amdgpu_device_ip_fini() skips its sw_fini and
amdgpu_bo_fini() (and thus ttm_device_fini()) is never called. The
freed device is left on ttm_glob.device_list.
Unwind on the failure paths after amdgpu_bo_init(): GART init failures
call amdgpu_bo_fini(); later failures (RAS sw init on v9-v12,
vm_fault_info allocation on v7/v8) also call amdgpu_vm_manager_fini().
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c | 10 ++++++++--
drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c | 10 ++++++++--
drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c | 10 ++++++++--
drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c | 6 +++++-
drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c | 14 +++++++++++---
drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c | 14 +++++++++++---
drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c | 10 ++++++++--
7 files changed, 59 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
index 49f593fe2a876..e59fee3955af0 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
@@ -861,7 +861,7 @@ static int gmc_v10_0_sw_init(struct amdgpu_ip_block *ip_block)
r = gmc_v10_0_gart_init(adev);
if (r)
- return r;
+ goto err_bo_fini;
/*
* number of VMs
@@ -880,9 +880,15 @@ static int gmc_v10_0_sw_init(struct amdgpu_ip_block *ip_block)
r = amdgpu_gmc_ras_sw_init(adev);
if (r)
- return r;
+ goto err_vm_fini;
return 0;
+
+err_vm_fini:
+ amdgpu_vm_manager_fini(adev);
+err_bo_fini:
+ amdgpu_bo_fini(adev);
+ return r;
}
/**
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c
index bc3b1ffb54886..e492a8fd8eb21 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c
@@ -859,7 +859,7 @@ static int gmc_v11_0_sw_init(struct amdgpu_ip_block *ip_block)
r = gmc_v11_0_gart_init(adev);
if (r)
- return r;
+ goto err_bo_fini;
/*
* number of VMs
@@ -879,9 +879,15 @@ static int gmc_v11_0_sw_init(struct amdgpu_ip_block *ip_block)
r = amdgpu_gmc_ras_sw_init(adev);
if (r)
- return r;
+ goto err_vm_fini;
return 0;
+
+err_vm_fini:
+ amdgpu_vm_manager_fini(adev);
+err_bo_fini:
+ amdgpu_bo_fini(adev);
+ return r;
}
/**
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c
index 3bb13cfed92fe..acebd6697372f 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c
@@ -987,7 +987,7 @@ static int gmc_v12_0_sw_init(struct amdgpu_ip_block *ip_block)
r = gmc_v12_0_gart_init(adev);
if (r)
- return r;
+ goto err_bo_fini;
if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(12, 1, 0))
gmc_v12_1_init_nps_details(adev);
@@ -1021,12 +1021,18 @@ static int gmc_v12_0_sw_init(struct amdgpu_ip_block *ip_block)
r = amdgpu_gmc_ras_sw_init(adev);
if (r)
- return r;
+ goto err_vm_fini;
if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(12, 1, 0))
amdgpu_gmc_sysfs_init(adev);
return 0;
+
+err_vm_fini:
+ amdgpu_vm_manager_fini(adev);
+err_bo_fini:
+ amdgpu_bo_fini(adev);
+ return r;
}
/**
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
index a7c353d1ac09d..925e9e243a143 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
@@ -817,7 +817,7 @@ static int gmc_v6_0_sw_init(struct amdgpu_ip_block *ip_block)
r = gmc_v6_0_gart_init(adev);
if (r)
- return r;
+ goto err_bo_fini;
/*
* number of VMs
@@ -840,6 +840,10 @@ static int gmc_v6_0_sw_init(struct amdgpu_ip_block *ip_block)
}
return 0;
+
+err_bo_fini:
+ amdgpu_bo_fini(adev);
+ return r;
}
static int gmc_v6_0_sw_fini(struct amdgpu_ip_block *ip_block)
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
index c09f5153679ea..3f3e4105bf3e6 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
@@ -999,7 +999,7 @@ static int gmc_v7_0_sw_init(struct amdgpu_ip_block *ip_block)
r = gmc_v7_0_gart_init(adev);
if (r)
- return r;
+ goto err_bo_fini;
/*
* number of VMs
@@ -1026,11 +1026,19 @@ static int gmc_v7_0_sw_init(struct amdgpu_ip_block *ip_block)
}
adev->gmc.vm_fault_info = kmalloc_obj(struct kfd_vm_fault_info);
- if (!adev->gmc.vm_fault_info)
- return -ENOMEM;
+ if (!adev->gmc.vm_fault_info) {
+ r = -ENOMEM;
+ goto err_vm_fini;
+ }
atomic_set_release(&adev->gmc.vm_fault_info_updated, 0);
return 0;
+
+err_vm_fini:
+ amdgpu_vm_manager_fini(adev);
+err_bo_fini:
+ amdgpu_bo_fini(adev);
+ return r;
}
static int gmc_v7_0_sw_fini(struct amdgpu_ip_block *ip_block)
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
index 15592027e7c0c..cb6d6e2259f3b 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
@@ -1114,7 +1114,7 @@ static int gmc_v8_0_sw_init(struct amdgpu_ip_block *ip_block)
r = gmc_v8_0_gart_init(adev);
if (r)
- return r;
+ goto err_bo_fini;
/*
* number of VMs
@@ -1141,11 +1141,19 @@ static int gmc_v8_0_sw_init(struct amdgpu_ip_block *ip_block)
}
adev->gmc.vm_fault_info = kmalloc_obj(struct kfd_vm_fault_info);
- if (!adev->gmc.vm_fault_info)
- return -ENOMEM;
+ if (!adev->gmc.vm_fault_info) {
+ r = -ENOMEM;
+ goto err_vm_fini;
+ }
atomic_set_release(&adev->gmc.vm_fault_info_updated, 0);
return 0;
+
+err_vm_fini:
+ amdgpu_vm_manager_fini(adev);
+err_bo_fini:
+ amdgpu_bo_fini(adev);
+ return r;
}
static int gmc_v8_0_sw_fini(struct amdgpu_ip_block *ip_block)
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
index a705830ef436c..136e4130b7926 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
@@ -2026,7 +2026,7 @@ static int gmc_v9_0_sw_init(struct amdgpu_ip_block *ip_block)
r = gmc_v9_0_gart_init(adev);
if (r)
- return r;
+ goto err_bo_fini;
gmc_v9_0_init_nps_details(adev);
/*
@@ -2066,12 +2066,18 @@ static int gmc_v9_0_sw_init(struct amdgpu_ip_block *ip_block)
r = amdgpu_gmc_ras_sw_init(adev);
if (r)
- return r;
+ goto err_vm_fini;
if (amdgpu_is_multi_aid(adev))
amdgpu_gmc_sysfs_init(adev);
return 0;
+
+err_vm_fini:
+ amdgpu_vm_manager_fini(adev);
+err_bo_fini:
+ amdgpu_bo_fini(adev);
+ return r;
}
static int gmc_v9_0_sw_fini(struct amdgpu_ip_block *ip_block)
--
2.43.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH 2/3] drm/amdgpu: unwind bo_init on GMC sw_init failure
2026-11-13 14:41 ` [PATCH 2/3] drm/amdgpu: unwind bo_init on GMC sw_init failure Mario Limonciello
@ 2026-11-13 14:56 ` sashiko-bot
2026-11-13 15:47 ` Mario Limonciello
0 siblings, 1 reply; 6+ messages in thread
From: sashiko-bot @ 2026-11-13 14:56 UTC (permalink / raw)
To: Mario Limonciello; +Cc: amd-gfx
Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [Medium] drm/amdgpu: gmc_v*_sw_init() calls amdgpu_bo_fini() with
GART/PDB0 BOs pinned
--
commit 4e2abeed7577cfdf2a67e81d9af414ebfbc361c6
Author: Mario Limonciello <mario.limonciello@amd.com>
drm/amdgpu: unwind bo_init on GMC sw_init failure
This commit unwinds amdgpu_bo_init() and amdgpu_vm_manager_init() when
gmc_v*_sw_init() fails after initializing the memory manager across GMC v6
through v12.
> diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
> index 49f593fe2a876..e59fee3955af0 100644
> --- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
> +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
> @@ -861,7 +861,7 @@ static int gmc_v10_0_sw_init(struct amdgpu_ip_block *ip_block)
>
> r = gmc_v10_0_gart_init(adev);
> if (r)
> - return r;
> + goto err_bo_fini;
>
> /*
> * number of VMs
> @@ -880,9 +880,15 @@ static int gmc_v10_0_sw_init(struct amdgpu_ip_block *ip_block)
>
> r = amdgpu_gmc_ras_sw_init(adev);
> if (r)
> - return r;
> + goto err_vm_fini;
>
> return 0;
> +
> +err_vm_fini:
> + amdgpu_vm_manager_fini(adev);
> +err_bo_fini:
> + amdgpu_bo_fini(adev);
> + return r;
> }
[Severity: Medium]
Does jumping to err_vm_fini tear down TTM while adev->gart.bo is still
pinned?
gmc_v10_0_gart_init() allocates and pins adev->gart.bo in VRAM. If
amdgpu_gmc_ras_sw_init() fails, err_vm_fini calls amdgpu_bo_fini() without
first freeing the GART table as gmc_v10_0_sw_fini() does. Because pinned
BOs cannot be evicted during amdgpu_ttm_fini(), gpu_buddy_fini() and
drm_mm_takedown() hit warnings and leak the pinned BOs and their backing
allocations.
The same missing GART cleanup affects the err_vm_fini paths in GMC v7, v8,
v9, v11, and v12. On GMC v9 and v12, gmc_v*_gart_init() also allocates
and pins adev->gmc.pdb0_bo when amdgpu_gmc_is_pdb0_enabled() is true, so
both err_vm_fini and a failure in amdgpu_gmc_pdb0_alloc() within
gmc_v*_gart_init() reach amdgpu_bo_fini() with pinned BOs still allocated.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261113-superm1-amdgpu-memory-leak-v1-0-4a495cfc2c92@amd.com?part=2
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 2/3] drm/amdgpu: unwind bo_init on GMC sw_init failure
2026-11-13 14:56 ` sashiko-bot
@ 2026-11-13 15:47 ` Mario Limonciello
0 siblings, 0 replies; 6+ messages in thread
From: Mario Limonciello @ 2026-11-13 15:47 UTC (permalink / raw)
To: sashiko-reviews; +Cc: amd-gfx
On 11/13/26 08:56, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential
> issue to consider:
> - [Medium] drm/amdgpu: gmc_v*_sw_init() calls amdgpu_bo_fini() with
> GART/PDB0 BOs pinned
> --
>
> commit 4e2abeed7577cfdf2a67e81d9af414ebfbc361c6
> Author: Mario Limonciello <mario.limonciello@amd.com>
>
> drm/amdgpu: unwind bo_init on GMC sw_init failure
>
> This commit unwinds amdgpu_bo_init() and amdgpu_vm_manager_init() when
> gmc_v*_sw_init() fails after initializing the memory manager across GMC v6
> through v12.
>
>> diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
>> index 49f593fe2a876..e59fee3955af0 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
>> +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
>> @@ -861,7 +861,7 @@ static int gmc_v10_0_sw_init(struct amdgpu_ip_block *ip_block)
>>
>> r = gmc_v10_0_gart_init(adev);
>> if (r)
>> - return r;
>> + goto err_bo_fini;
>>
>> /*
>> * number of VMs
>> @@ -880,9 +880,15 @@ static int gmc_v10_0_sw_init(struct amdgpu_ip_block *ip_block)
>>
>> r = amdgpu_gmc_ras_sw_init(adev);
>> if (r)
>> - return r;
>> + goto err_vm_fini;
>>
>> return 0;
>> +
>> +err_vm_fini:
>> + amdgpu_vm_manager_fini(adev);
>> +err_bo_fini:
>> + amdgpu_bo_fini(adev);
>> + return r;
>> }
>
> [Severity: Medium]
> Does jumping to err_vm_fini tear down TTM while adev->gart.bo is still
> pinned?
>
> gmc_v10_0_gart_init() allocates and pins adev->gart.bo in VRAM. If
> amdgpu_gmc_ras_sw_init() fails, err_vm_fini calls amdgpu_bo_fini() without
> first freeing the GART table as gmc_v10_0_sw_fini() does. Because pinned
> BOs cannot be evicted during amdgpu_ttm_fini(), gpu_buddy_fini() and
> drm_mm_takedown() hit warnings and leak the pinned BOs and their backing
> allocations.
>
> The same missing GART cleanup affects the err_vm_fini paths in GMC v7, v8,
> v9, v11, and v12. On GMC v9 and v12, gmc_v*_gart_init() also allocates
> and pins adev->gmc.pdb0_bo when amdgpu_gmc_is_pdb0_enabled() is true, so
> both err_vm_fini and a failure in amdgpu_gmc_pdb0_alloc() within
> gmc_v*_gart_init() reach amdgpu_bo_fini() with pinned BOs still allocated.
>
This finding looks correct. I'll re-spin.
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 3/3] drm/amdgpu: release WC memtype and MTRR when amdgpu_bo_init() fails
2026-11-13 14:41 [PATCH 0/3] drm/amdgpu: fix TTM device_list use-after-free on failed probe Mario Limonciello
2026-11-13 14:41 ` [PATCH 1/3] drm/amdgpu: unwind TTM on amdgpu_ttm_init() failure Mario Limonciello
2026-11-13 14:41 ` [PATCH 2/3] drm/amdgpu: unwind bo_init on GMC sw_init failure Mario Limonciello
@ 2026-11-13 14:41 ` Mario Limonciello
2 siblings, 0 replies; 6+ messages in thread
From: Mario Limonciello @ 2026-11-13 14:41 UTC (permalink / raw)
To: Alex Deucher, Christian König; +Cc: amd-gfx, Mario Limonciello
amdgpu_bo_init() reserves the WC memtype for the VRAM aperture and adds
an MTRR before calling amdgpu_ttm_init(). If amdgpu_ttm_init() fails,
the GMC sw_init callers just return the error and GMC's sw_fini is never
run, so amdgpu_bo_fini(), the only place that drops the memtype and MTRR,
is never called. A later rebind then reserves the same aperture again
with the old reservation still held.
Undo the memtype reservation and the MTRR in amdgpu_bo_init() itself when
amdgpu_ttm_init() fails.
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 20 +++++++++++++++++---
1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
index 6aa895f63aeaf..0b34458301f3f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
@@ -1108,11 +1108,13 @@ static const char * const amdgpu_vram_names[] = {
*/
int amdgpu_bo_init(struct amdgpu_device *adev)
{
+ int r;
+
/* On A+A platform, VRAM can be mapped as WB */
if (!adev->gmc.xgmi.connected_to_cpu && !adev->gmc.is_app_apu) {
/* reserve PAT memory space to WC for VRAM */
- int r = arch_io_reserve_memtype_wc(adev->gmc.aper_base,
- adev->gmc.aper_size);
+ r = arch_io_reserve_memtype_wc(adev->gmc.aper_base,
+ adev->gmc.aper_size);
if (r) {
DRM_ERROR("Unable to set WC memtype for the aperture base\n");
@@ -1129,7 +1131,19 @@ int amdgpu_bo_init(struct amdgpu_device *adev)
(unsigned long long)adev->gmc.aper_size >> 20);
drm_info(adev_to_drm(adev), "RAM width %dbits %s\n",
adev->gmc.vram_width, amdgpu_vram_names[adev->gmc.vram_type]);
- return amdgpu_ttm_init(adev);
+
+ r = amdgpu_ttm_init(adev);
+ if (r) {
+ /* the caller does not call amdgpu_bo_fini() when we fail */
+ if (!adev->gmc.xgmi.connected_to_cpu && !adev->gmc.is_app_apu) {
+ arch_phys_wc_del(adev->gmc.vram_mtrr);
+ arch_io_free_memtype_wc(adev->gmc.aper_base,
+ adev->gmc.aper_size);
+ }
+ return r;
+ }
+
+ return 0;
}
/**
--
2.43.0
^ permalink raw reply related [flat|nested] 6+ messages in thread