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.

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:

  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.

Fixes: 037b98a2312e ("drm/amdgpu: move UVD and VCE sched entity init after 
sched init")
Cc: Alex Deucher <[email protected]>
Cc: Christian König <[email protected]>
Signed-off-by: Olivier Kaloudoff <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 3 ++-
 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 ecd7caa95..cd35ff7ca 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 1f7a98cdc..3952af9ae 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]);
-- 
2.39.5

Reply via email to