On Sun, Jun 28, 2026 at 12:39 PM Geoffrey McRae <[email protected]> wrote:
>
> DM I2C adapters can remain visible to userspace while DM teardown is
> already in progress. A concurrent i2c-dev transfer may then enter
> amdgpu_dm_i2c_xfer() after the backing DM state has been torn down,
> leading to a NULL pointer dereference.
>
> Create a devres group around the DM I2C adapter lifetime and release it
> at the start of dm_hw_fini(), before HPD, IRQ, and DM state are torn
> down. This removes the I2C adapters first and waits for in-flight users
> to drain before the structures used by amdgpu_dm_i2c_xfer() disappear.
>
> This fixes a teardown ordering race seen during device removal:
>
> BUG: kernel NULL pointer dereference
> RIP: amdgpu_dm_i2c_xfer+0x122/0x1c0 [amdgpu]
> Call Trace:
> __i2c_transfer
> i2c_transfer
> i2cdev_ioctl_rdwr
>
> 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]>

Acked-by: Alex Deucher <[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