]> git.hungrycats.org Git - linux/commitdiff
drm/radeon: avoid double free in r600 DPM cleanup
authorRuoyu Wang <ruoyuw560@gmail.com>
Mon, 8 Jun 2026 06:36:38 +0000 (14:36 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 17 Jun 2026 20:23:16 +0000 (16:23 -0400)
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@gmail.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/radeon/r600_dpm.c

index 83f1ae31cbdbc8bf6d89f91321580d119fd5409d..9755e717ca8bb2686a4a9d2eeebf6e5e159eee54 100644 (file)
@@ -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,