diff options
| author | Olivier Kaloudoff <olivier.kaloudoff@gmail.com> | 2026-10-15 21:30:37 +0200 |
|---|---|---|
| committer | Alex Deucher <alexander.deucher@amd.com> | 2026-10-27 17:03:03 -0400 |
| commit | c3fed6272bb4771a849c33c781af99afa90e90ad (patch) | |
| tree | 5af360c540783051a8220c28538a529133f4c708 | |
| parent | 3254ed0b15f2fe656c9cb36ccb59b92422440bf8 (diff) | |
drm/amdgpu: guard VCE/UVD sched entity teardown on failed probe
Since commit 037b98a2312e ("drm/amdgpu: move UVD and VCE sched entity
init after sched init"), drm_sched_entity_init() for the VCE and UVD
kernel entities runs in the scheduler-init phase, well after the
IP-block sw_init phase has allocated the vcpu_bos.
If probe fails between the two phases, amdgpu_device_fini_sw() still
runs the per-IP sw_fini callbacks for blocks that did complete
sw_init. Both amdgpu_vce_sw_fini() and amdgpu_uvd_sw_fini() then call
drm_sched_entity_destroy() on an entity that was never initialized:
entity->rq is NULL and drm_sched_entity_flush() dereferences it,
oopsing in whatever context drove the failed probe.
The hole was latent-but-safe until commit 2df5efb45425 ("drm/sched:
Remove redundant entity->rq initialization and checks") removed the
if (!entity->rq) early return that commit 1decbf6bb0b4 ("drm/sched:
Fix entities with 0 rqs.") had put in drm_sched_entity_flush(), on the
grounds that entity->rq can never be NULL. That holds only for
entities that completed drm_sched_entity_init() — not for the
never-initialized entity this teardown path reaches.
Observed on real hardware: MI50 (Vega20, VCE 4.0 / UVD 7.2) behind a
Thunderbolt link — a pciehp presence/link-change event re-probes the
device; when the re-probe fails (-EINVAL here), the cleanup path
NULL-derefs inside drm_sched_entity_flush() in the pciehp IRQ thread
and takes the whole machine down (panic_on_oops, EFI pstore capture).
Reproduced twice on 7.3-rc5, 2026-10-06 and 2026-10-09, identical
signature; the faulting instruction is `mov (%rax),%r15` on rax =
entity->rq == NULL, i.e. `sched = entity->rq->sched`:
BUG: kernel NULL pointer dereference
RIP: drm_sched_entity_flush+0x34/0x2d0 [gpu_sched]
drm_sched_entity_destroy
amdgpu_vce_sw_fini
vce_v4_0_sw_fini
amdgpu_device_fini_sw
...
pciehp_configure_device
pciehp_handle_presence_or_link_change
Guard the entity teardown on entity->rq, which is set only by
drm_sched_entity_init(). amdgpu_ring_fini() already self-guards via
the rings[] registration, and the vcpu_bo/firmware cleanup still runs
as before.
v2: retarget Fixes: at commit 2df5efb45425 ("drm/sched: Remove
redundant entity->rq initialization and checks") — the !entity->rq
check from commit 1decbf6bb0b4 ("drm/sched: Fix entities with 0
rqs.") that Alex pointed to was removed by it in the 7.3 window,
so this is a regression there, not a pre-existing hole.
Fixes: 2df5efb45425 ("drm/sched: Remove redundant entity->rq initialization and checks")
Cc: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
Cc: Philipp Stanner <phasta@kernel.org>
Cc: Alex Deucher <alexander.deucher@amd.com>
Cc: Christian König <christian.koenig@amd.com>
Signed-off-by: Olivier Kaloudoff <olivier.kaloudoff@gmail.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit 3ad55d18f468fa81be725301d1e138ecd5148e6a)
Cc: stable@vger.kernel.org
| -rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 3 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 3 |
2 files changed, 4 insertions, 2 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index ecd7caa95d4b..cd35ff7ca864 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -377,7 +377,8 @@ int amdgpu_uvd_sw_fini(struct amdgpu_device *adev) void *addr = amdgpu_bo_kptr(adev->uvd.ib_bo); int i, j; - drm_sched_entity_destroy(&adev->uvd.entity); + if (adev->uvd.entity.rq) + drm_sched_entity_destroy(&adev->uvd.entity); for (j = 0; j < adev->uvd.num_uvd_inst; ++j) { if (adev->uvd.harvest_config & (1 << j)) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index 1f7a98cdce5a..3952af9ae115 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -253,7 +253,8 @@ int amdgpu_vce_sw_fini(struct amdgpu_device *adev) if (adev->vce.vcpu_bo == NULL) return 0; - drm_sched_entity_destroy(&adev->vce.entity); + if (adev->vce.entity.rq) + drm_sched_entity_destroy(&adev->vce.entity); for (i = 0; i < adev->vce.num_rings; i++) amdgpu_ring_fini(&adev->vce.ring[i]); |
