When tearing down the AMDGPU display manager, the i2c devres group
was being released before the i2c adapters were fully torn down.
This caused a race condition where i2c transfers could still be in
progress during device teardown, leading to a NULL pointer dereference.

The fix ensures that the i2c devres group is properly closed during
initialization and released during teardown, maintaining proper
lifetime management of i2c adapters.

Fixes: 5b3eca05cfb0 ("drm/amd/display: Use devm_i2c_add_adapter to simplify i2c 
cleanup logic")
Signed-off-by: Geoffrey McRae <[email protected]>
Cc: Alex Deucher <[email protected]>
Cc: Christian König <[email protected]>
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 14 +++++++++++++-
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  7 +++++++
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index b97ceabe6173..5613dc9903fe 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -1496,17 +1496,26 @@ static int dm_hw_init(struct amdgpu_ip_block *ip_block)
        struct amdgpu_device *adev = ip_block->adev;
        int r;
 
+       adev->dm.i2c_devres_group = devres_open_group(adev->dev, NULL, 
GFP_KERNEL);
+       if (!adev->dm.i2c_devres_group)
+               return -ENOMEM;
+
        /* Create DAL display manager */
        r = amdgpu_dm_init(adev);
        if (r)
-               return r;
+               goto err_release_i2c;
        amdgpu_dm_hpd_init(adev);
 
        r = dm_oem_i2c_hw_init(adev);
        if (r)
                drm_info(adev_to_drm(adev), "Failed to add OEM i2c bus\n");
 
+       devres_close_group(adev->dev, adev->dm.i2c_devres_group);
        return 0;
+
+err_release_i2c:
+       devres_release_group(adev->dev, adev->dm.i2c_devres_group);
+       return r;
 }
 
 /**
@@ -1521,6 +1530,9 @@ static int dm_hw_fini(struct amdgpu_ip_block *ip_block)
 {
        struct amdgpu_device *adev = ip_block->adev;
 
+       if (adev->dm.i2c_devres_group)
+               devres_release_group(adev->dev, adev->dm.i2c_devres_group);
+
        amdgpu_dm_hpd_fini(adev);
 
        amdgpu_dm_irq_fini(adev);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index 909ee71d6d59..13a18e1ed576 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -688,6 +688,13 @@ struct amdgpu_display_manager {
         */
        void *bb_from_dmub;
 
+       /**
+        * @i2c_devres_group:
+        *
+        * Devres group for DM i2c adapter lifetime management.
+        */
+       void *i2c_devres_group;
+
        /**
         * @oem_i2c:
         *
-- 
2.43.0

Reply via email to