mirror of
https://github.com/torvalds/linux.git
synced 2024-11-08 21:21:47 +00:00
drm/radeon/dpm: use multiple UVD power states (v3)
Use the UVD handle information to determine which which power states to select when using UVD. For example, decoding a single SD stream requires much lower clocks than multiple HD streams. v2: switch to a cleaner dpm/uvd interface v3: change the uvd power state while streams are active if need be Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
85a129ca8d
commit
ce3537d571
@ -1360,11 +1360,14 @@ struct radeon_dpm {
|
||||
struct radeon_dpm_thermal thermal;
|
||||
/* forced levels */
|
||||
enum radeon_dpm_forced_level forced_level;
|
||||
/* track UVD streams */
|
||||
unsigned sd;
|
||||
unsigned hd;
|
||||
};
|
||||
|
||||
void radeon_dpm_enable_power_state(struct radeon_device *rdev,
|
||||
enum radeon_pm_state_type dpm_state);
|
||||
|
||||
void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable);
|
||||
|
||||
struct radeon_pm {
|
||||
struct mutex mutex;
|
||||
|
@ -383,6 +383,10 @@ static int radeon_cs_ib_chunk(struct radeon_device *rdev,
|
||||
DRM_ERROR("Invalid command stream !\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
if (parser->ring == R600_RING_TYPE_UVD_INDEX)
|
||||
radeon_uvd_note_usage(rdev);
|
||||
|
||||
radeon_cs_sync_rings(parser);
|
||||
r = radeon_ib_schedule(rdev, &parser->ib, NULL);
|
||||
if (r) {
|
||||
@ -474,6 +478,9 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev,
|
||||
return r;
|
||||
}
|
||||
|
||||
if (parser->ring == R600_RING_TYPE_UVD_INDEX)
|
||||
radeon_uvd_note_usage(rdev);
|
||||
|
||||
mutex_lock(&rdev->vm_manager.lock);
|
||||
mutex_lock(&vm->mutex);
|
||||
r = radeon_vm_alloc_pt(rdev, vm);
|
||||
@ -552,10 +559,6 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* XXX pick SD/HD/MVC */
|
||||
if (parser.ring == R600_RING_TYPE_UVD_INDEX)
|
||||
radeon_uvd_note_usage(rdev);
|
||||
|
||||
r = radeon_cs_ib_chunk(rdev, &parser);
|
||||
if (r) {
|
||||
goto out;
|
||||
|
@ -729,6 +729,8 @@ restart_search:
|
||||
/* use a fallback state if we didn't match */
|
||||
switch (dpm_state) {
|
||||
case POWER_STATE_TYPE_INTERNAL_UVD_SD:
|
||||
dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD;
|
||||
goto restart_search;
|
||||
case POWER_STATE_TYPE_INTERNAL_UVD_HD:
|
||||
case POWER_STATE_TYPE_INTERNAL_UVD_HD2:
|
||||
case POWER_STATE_TYPE_INTERNAL_UVD_MVC:
|
||||
@ -884,6 +886,34 @@ void radeon_dpm_enable_power_state(struct radeon_device *rdev,
|
||||
radeon_pm_compute_clocks(rdev);
|
||||
}
|
||||
|
||||
void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable)
|
||||
{
|
||||
enum radeon_pm_state_type dpm_state;
|
||||
|
||||
if (enable) {
|
||||
mutex_lock(&rdev->pm.mutex);
|
||||
rdev->pm.dpm.uvd_active = true;
|
||||
if ((rdev->pm.dpm.sd == 1) && (rdev->pm.dpm.hd == 0))
|
||||
dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_SD;
|
||||
else if ((rdev->pm.dpm.sd == 2) && (rdev->pm.dpm.hd == 0))
|
||||
dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD;
|
||||
else if ((rdev->pm.dpm.sd == 0) && (rdev->pm.dpm.hd == 1))
|
||||
dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD;
|
||||
else if ((rdev->pm.dpm.sd == 0) && (rdev->pm.dpm.hd == 2))
|
||||
dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD2;
|
||||
else
|
||||
dpm_state = POWER_STATE_TYPE_INTERNAL_UVD;
|
||||
rdev->pm.dpm.state = dpm_state;
|
||||
mutex_unlock(&rdev->pm.mutex);
|
||||
} else {
|
||||
mutex_lock(&rdev->pm.mutex);
|
||||
rdev->pm.dpm.uvd_active = false;
|
||||
mutex_unlock(&rdev->pm.mutex);
|
||||
}
|
||||
|
||||
radeon_pm_compute_clocks(rdev);
|
||||
}
|
||||
|
||||
static void radeon_pm_suspend_old(struct radeon_device *rdev)
|
||||
{
|
||||
mutex_lock(&rdev->pm.mutex);
|
||||
|
@ -775,10 +775,7 @@ static void radeon_uvd_idle_work_handler(struct work_struct *work)
|
||||
|
||||
if (radeon_fence_count_emitted(rdev, R600_RING_TYPE_UVD_INDEX) == 0) {
|
||||
if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
|
||||
mutex_lock(&rdev->pm.mutex);
|
||||
rdev->pm.dpm.uvd_active = false;
|
||||
mutex_unlock(&rdev->pm.mutex);
|
||||
radeon_pm_compute_clocks(rdev);
|
||||
radeon_dpm_enable_uvd(rdev, false);
|
||||
} else {
|
||||
radeon_set_uvd_clocks(rdev, 0, 0);
|
||||
}
|
||||
@ -790,13 +787,25 @@ static void radeon_uvd_idle_work_handler(struct work_struct *work)
|
||||
|
||||
void radeon_uvd_note_usage(struct radeon_device *rdev)
|
||||
{
|
||||
bool streams_changed = false;
|
||||
bool set_clocks = !cancel_delayed_work_sync(&rdev->uvd.idle_work);
|
||||
set_clocks &= schedule_delayed_work(&rdev->uvd.idle_work,
|
||||
msecs_to_jiffies(UVD_IDLE_TIMEOUT_MS));
|
||||
if (set_clocks) {
|
||||
|
||||
if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
|
||||
/* XXX pick SD/HD/MVC */
|
||||
radeon_dpm_enable_power_state(rdev, POWER_STATE_TYPE_INTERNAL_UVD);
|
||||
unsigned hd = 0, sd = 0;
|
||||
radeon_uvd_count_handles(rdev, &sd, &hd);
|
||||
if ((rdev->pm.dpm.sd != sd) ||
|
||||
(rdev->pm.dpm.hd != hd)) {
|
||||
rdev->pm.dpm.sd = sd;
|
||||
rdev->pm.dpm.hd = hd;
|
||||
streams_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (set_clocks || streams_changed) {
|
||||
if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
|
||||
radeon_dpm_enable_uvd(rdev, true);
|
||||
} else {
|
||||
radeon_set_uvd_clocks(rdev, 53300, 40000);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user