From d3f30034f861a585f8e487ae1555d9f288a96f87 Mon Sep 17 00:00:00 2001 From: Ruoyu Wang Date: Mon, 8 Jun 2026 14:36:38 +0800 Subject: [PATCH] drm/radeon: avoid double free in r600 DPM cleanup 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 Signed-off-by: Alex Deucher --- 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 83f1ae31cbdb..9755e717ca8b 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,