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 >
