Re: [PATCH] drm/radeon: avoid double free in r600 DPM cleanup

From: Alex Deucher

Date: Mon Jun 15 2026 - 11:15:49 EST


On Mon, Jun 8, 2026 at 5:14 AM Ruoyu Wang <ruoyuw560@xxxxxxxxx> wrote:
>
> r600_parse_extended_power_table() uses manual kfree() calls for some
> early allocation failures, but the freed pointers are left in the
> dynamic power-management state. If device teardown later calls
> r600_free_extended_power_table(), those stale pointers can be freed
> again.
>
> Use the common extended power table cleanup helper for those early
> failure paths as well, and clear each pointer after freeing it so
> repeated cleanup stays safe.
>
> Signed-off-by: Ruoyu Wang <ruoyuw560@xxxxxxxxx>

Applied. Thanks!

> ---
> drivers/gpu/drm/radeon/r600_dpm.c | 21 +++++++++++++++------
> 1 file changed, 15 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/gpu/drm/radeon/r600_dpm.c b/drivers/gpu/drm/radeon/r600_dpm.c
> index 83f1ae31cbdbc..9755e717ca8bb 100644
> --- a/drivers/gpu/drm/radeon/r600_dpm.c
> +++ b/drivers/gpu/drm/radeon/r600_dpm.c
> @@ -932,7 +932,7 @@ int r600_parse_extended_power_table(struct radeon_device *rdev)
> ret = r600_parse_clk_voltage_dep_table(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
> dep_table);
> if (ret) {
> - kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries);
> + r600_free_extended_power_table(rdev);
> return ret;
> }
> }
> @@ -943,8 +943,7 @@ int r600_parse_extended_power_table(struct radeon_device *rdev)
> ret = r600_parse_clk_voltage_dep_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
> dep_table);
> if (ret) {
> - kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries);
> - kfree(rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries);
> + r600_free_extended_power_table(rdev);
> return ret;
> }
> }
> @@ -955,9 +954,7 @@ int r600_parse_extended_power_table(struct radeon_device *rdev)
> ret = r600_parse_clk_voltage_dep_table(&rdev->pm.dpm.dyn_state.mvdd_dependency_on_mclk,
> dep_table);
> if (ret) {
> - kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries);
> - kfree(rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries);
> - kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries);
> + r600_free_extended_power_table(rdev);
> return ret;
> }
> }
> @@ -1296,17 +1293,29 @@ void r600_free_extended_power_table(struct radeon_device *rdev)
> struct radeon_dpm_dynamic_state *dyn_state = &rdev->pm.dpm.dyn_state;
>
> kfree(dyn_state->vddc_dependency_on_sclk.entries);
> + dyn_state->vddc_dependency_on_sclk.entries = NULL;
> kfree(dyn_state->vddci_dependency_on_mclk.entries);
> + dyn_state->vddci_dependency_on_mclk.entries = NULL;
> kfree(dyn_state->vddc_dependency_on_mclk.entries);
> + dyn_state->vddc_dependency_on_mclk.entries = NULL;
> kfree(dyn_state->mvdd_dependency_on_mclk.entries);
> + dyn_state->mvdd_dependency_on_mclk.entries = NULL;
> kfree(dyn_state->cac_leakage_table.entries);
> + dyn_state->cac_leakage_table.entries = NULL;
> kfree(dyn_state->phase_shedding_limits_table.entries);
> + dyn_state->phase_shedding_limits_table.entries = NULL;
> kfree(dyn_state->ppm_table);
> + dyn_state->ppm_table = NULL;
> kfree(dyn_state->cac_tdp_table);
> + dyn_state->cac_tdp_table = NULL;
> kfree(dyn_state->vce_clock_voltage_dependency_table.entries);
> + dyn_state->vce_clock_voltage_dependency_table.entries = NULL;
> kfree(dyn_state->uvd_clock_voltage_dependency_table.entries);
> + dyn_state->uvd_clock_voltage_dependency_table.entries = NULL;
> kfree(dyn_state->samu_clock_voltage_dependency_table.entries);
> + dyn_state->samu_clock_voltage_dependency_table.entries = NULL;
> kfree(dyn_state->acp_clock_voltage_dependency_table.entries);
> + dyn_state->acp_clock_voltage_dependency_table.entries = NULL;
> }
>
> enum radeon_pcie_gen r600_get_pcie_gen_support(struct radeon_device *rdev,
> --
> 2.51.0
>