On 2026-07-08 09:30, Alex Deucher wrote:
> 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]>
Reviewed-by: Leo Li <[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
>>