mirror of
https://github.com/torvalds/linux.git
synced 2026-10-30 14:06:03 +01:00
drm/amdgpu: fix ACP MFD device leak on init failure
acp_hw_init() registers ACP child devices with mfd_add_devices() before attaching them to the ACP power domain and initializing the hardware. If attaching a child to the power domain fails, or if the ACP reset or clock enable operation times out, the failure path frees only the source cell, resource, and platform-data allocations. The child platform devices already registered by mfd_add_devices() remain registered and are never released. Remove the children from the power domain and unregister the MFD devices on failures that occur after mfd_add_devices() succeeds. Keep mfd_add_devices() failures on the existing cleanup path since the MFD core already rolls back partially registered children itself. The issue was identified by a static analysis tool I developed and confirmed by manual review. Fixes:25030321ba("drm/amd: add pm domain for ACP IP sub blocks") Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> (cherry picked from commit63da68d6a2) Cc: stable@vger.kernel.org
This commit is contained in:
parent
f5a5add360
commit
f001304615
|
|
@ -318,7 +318,7 @@ static int acp_hw_init(struct amdgpu_ip_block *ip_block)
|
|||
r = device_for_each_child(adev->acp.parent, &adev->acp.acp_genpd->gpd,
|
||||
acp_genpd_add_device);
|
||||
if (r)
|
||||
goto failure;
|
||||
goto failure_remove_mfd;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
@ -443,7 +443,7 @@ static int acp_hw_init(struct amdgpu_ip_block *ip_block)
|
|||
r = device_for_each_child(adev->acp.parent, &adev->acp.acp_genpd->gpd,
|
||||
acp_genpd_add_device);
|
||||
if (r)
|
||||
goto failure;
|
||||
goto failure_remove_mfd;
|
||||
}
|
||||
|
||||
/* Assert Soft reset of ACP */
|
||||
|
|
@ -461,7 +461,7 @@ static int acp_hw_init(struct amdgpu_ip_block *ip_block)
|
|||
if (--count == 0) {
|
||||
dev_err(&adev->pdev->dev, "Failed to reset ACP\n");
|
||||
r = -ETIMEDOUT;
|
||||
goto failure;
|
||||
goto failure_remove_mfd;
|
||||
}
|
||||
udelay(100);
|
||||
}
|
||||
|
|
@ -479,7 +479,7 @@ static int acp_hw_init(struct amdgpu_ip_block *ip_block)
|
|||
if (--count == 0) {
|
||||
dev_err(&adev->pdev->dev, "Failed to reset ACP\n");
|
||||
r = -ETIMEDOUT;
|
||||
goto failure;
|
||||
goto failure_remove_mfd;
|
||||
}
|
||||
udelay(100);
|
||||
}
|
||||
|
|
@ -489,6 +489,11 @@ static int acp_hw_init(struct amdgpu_ip_block *ip_block)
|
|||
cgs_write_register(adev->acp.cgs_device, mmACP_SOFT_RESET, val);
|
||||
return 0;
|
||||
|
||||
failure_remove_mfd:
|
||||
device_for_each_child(adev->acp.parent, NULL,
|
||||
acp_genpd_remove_device);
|
||||
mfd_remove_devices(adev->acp.parent);
|
||||
|
||||
failure:
|
||||
kfree(adev->acp.i2s_pdata);
|
||||
kfree(adev->acp.acp_res);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user