diff --git a/sys/dev/drm/radeon/kv_dpm.c b/sys/dev/drm/radeon/kv_dpm.c index 1111111..2222222 100644 --- a/sys/dev/drm/radeon/kv_dpm.c +++ b/sys/dev/drm/radeon/kv_dpm.c @@ -2670,12 +2670,20 @@ static int kv_parse_power_table(struct radeon_device *rdev) power_state = (union pplib_power_state *)power_state_offset; non_clock_array_index = power_state->v2.nonClockInfoIndex; non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) &non_clock_info_array->nonClockInfo[non_clock_array_index]; if (!rdev->pm.power_state[i].clock_info) - return -EINVAL; + goto parse_error; ps = kzalloc(sizeof(struct kv_ps), GFP_KERNEL); if (ps == NULL) { - kfree(rdev->pm.dpm.ps); + /* free the states parsed so far and drop the + * dangling pointer so kv_dpm_fini cannot double + * free it (and does free the ps_priv objects) */ + for (j = 0; j < i; j++) + kfree(rdev->pm.dpm.ps[j].ps_priv); + kfree(rdev->pm.dpm.ps); + rdev->pm.dpm.ps = NULL; + rdev->pm.dpm.num_ps = 0; return -ENOMEM; } + /* count states as they complete so error paths can unwind */ + rdev->pm.dpm.num_ps = i + 1; rdev->pm.dpm.ps[i].ps_priv = ps; @@ -2698,7 +2706,6 @@ static int kv_parse_power_table(struct radeon_device *rdev) power_state_offset += 2 + power_state->v2.ucNumDPMLevels; } - rdev->pm.dpm.num_ps = state_array->ucNumEntries; + /* num_ps was updated incrementally above */ /* fill in the vce power states */ # NOTE: 'j' is already declared in the function (int i, j, k, ...). # Companion (out of audited scope): honor kv_dpm_init()'s return value at # radeon_pm.c:1448 so the error is not silently swallowed (see DF-3953).