mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 20:54:03 +02:00
drm/amd/display: Fix DM I2C teardown race
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: 5b3eca05cf ("drm/amd/display: Use devm_i2c_add_adapter to simplify i2c cleanup logic")
Signed-off-by: Geoffrey McRae <geoffrey.mcrae@amd.com>
Acked-by: Alex Deucher <alexander.deucher@amd.com>
Reviewed-by: Leo Li <sunpeng.li@amd.com>
Cc: Alex Deucher <alexander.deucher@amd.com>
Cc: Christian König <christian.koenig@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
da805bfb3d
commit
e4ae30a12a
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user