drm/amdgpu: use begin/end_use for VCE power/clock gating

This fixes turning power and clock on when it is actually needed.

Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Edward O'Callaghan <funfunctor@folklore1984.net>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Christian König 2016-07-20 16:53:36 +02:00 committed by Alex Deucher
parent c4120d55ff
commit ebff485e93
5 changed files with 31 additions and 13 deletions

View File

@ -1702,6 +1702,7 @@ struct amdgpu_vce {
struct drm_file *filp[AMDGPU_MAX_VCE_HANDLES]; struct drm_file *filp[AMDGPU_MAX_VCE_HANDLES];
uint32_t img_size[AMDGPU_MAX_VCE_HANDLES]; uint32_t img_size[AMDGPU_MAX_VCE_HANDLES];
struct delayed_work idle_work; struct delayed_work idle_work;
struct mutex idle_mutex;
const struct firmware *fw; /* VCE firmware */ const struct firmware *fw; /* VCE firmware */
struct amdgpu_ring ring[AMDGPU_MAX_VCE_RINGS]; struct amdgpu_ring ring[AMDGPU_MAX_VCE_RINGS];
struct amdgpu_irq_src irq; struct amdgpu_irq_src irq;

View File

@ -85,8 +85,6 @@ int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size)
unsigned ucode_version, version_major, version_minor, binary_id; unsigned ucode_version, version_major, version_minor, binary_id;
int i, r; int i, r;
INIT_DELAYED_WORK(&adev->vce.idle_work, amdgpu_vce_idle_work_handler);
switch (adev->asic_type) { switch (adev->asic_type) {
#ifdef CONFIG_DRM_AMDGPU_CIK #ifdef CONFIG_DRM_AMDGPU_CIK
case CHIP_BONAIRE: case CHIP_BONAIRE:
@ -197,6 +195,9 @@ int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size)
adev->vce.filp[i] = NULL; adev->vce.filp[i] = NULL;
} }
INIT_DELAYED_WORK(&adev->vce.idle_work, amdgpu_vce_idle_work_handler);
mutex_init(&adev->vce.idle_mutex);
return 0; return 0;
} }
@ -220,6 +221,7 @@ int amdgpu_vce_sw_fini(struct amdgpu_device *adev)
amdgpu_ring_fini(&adev->vce.ring[1]); amdgpu_ring_fini(&adev->vce.ring[1]);
release_firmware(adev->vce.fw); release_firmware(adev->vce.fw);
mutex_destroy(&adev->vce.idle_mutex);
return 0; return 0;
} }
@ -315,19 +317,19 @@ static void amdgpu_vce_idle_work_handler(struct work_struct *work)
} }
/** /**
* amdgpu_vce_note_usage - power up VCE * amdgpu_vce_ring_begin_use - power up VCE
* *
* @adev: amdgpu_device pointer * @ring: amdgpu ring
* *
* Make sure VCE is powerd up when we want to use it * Make sure VCE is powerd up when we want to use it
*/ */
static void amdgpu_vce_note_usage(struct amdgpu_device *adev) void amdgpu_vce_ring_begin_use(struct amdgpu_ring *ring)
{ {
bool set_clocks = !cancel_delayed_work_sync(&adev->vce.idle_work); struct amdgpu_device *adev = ring->adev;
bool set_clocks;
set_clocks &= schedule_delayed_work(&adev->vce.idle_work,
VCE_IDLE_TIMEOUT);
mutex_lock(&adev->vce.idle_mutex);
set_clocks = !cancel_delayed_work_sync(&adev->vce.idle_work);
if (set_clocks) { if (set_clocks) {
if (adev->pm.dpm_enabled) { if (adev->pm.dpm_enabled) {
amdgpu_dpm_enable_vce(adev, true); amdgpu_dpm_enable_vce(adev, true);
@ -335,6 +337,19 @@ static void amdgpu_vce_note_usage(struct amdgpu_device *adev)
amdgpu_asic_set_vce_clocks(adev, 53300, 40000); amdgpu_asic_set_vce_clocks(adev, 53300, 40000);
} }
} }
mutex_unlock(&adev->vce.idle_mutex);
}
/**
* amdgpu_vce_ring_end_use - power VCE down
*
* @ring: amdgpu ring
*
* Schedule work to power VCE down again
*/
void amdgpu_vce_ring_end_use(struct amdgpu_ring *ring)
{
schedule_delayed_work(&ring->adev->vce.idle_work, VCE_IDLE_TIMEOUT);
} }
/** /**
@ -355,8 +370,6 @@ void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file *filp)
if (!handle || adev->vce.filp[i] != filp) if (!handle || adev->vce.filp[i] != filp)
continue; continue;
amdgpu_vce_note_usage(adev);
r = amdgpu_vce_get_destroy_msg(ring, handle, false, NULL); r = amdgpu_vce_get_destroy_msg(ring, handle, false, NULL);
if (r) if (r)
DRM_ERROR("Error destroying VCE handle (%d)!\n", r); DRM_ERROR("Error destroying VCE handle (%d)!\n", r);
@ -622,8 +635,6 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx)
uint32_t *size = &tmp; uint32_t *size = &tmp;
int i, r = 0, idx = 0; int i, r = 0, idx = 0;
amdgpu_vce_note_usage(p->adev);
while (idx < ib->length_dw) { while (idx < ib->length_dw) {
uint32_t len = amdgpu_get_ib_value(p, ib_idx, idx); uint32_t len = amdgpu_get_ib_value(p, ib_idx, idx);
uint32_t cmd = amdgpu_get_ib_value(p, ib_idx, idx + 1); uint32_t cmd = amdgpu_get_ib_value(p, ib_idx, idx + 1);

View File

@ -40,5 +40,7 @@ void amdgpu_vce_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq,
unsigned flags); unsigned flags);
int amdgpu_vce_ring_test_ring(struct amdgpu_ring *ring); int amdgpu_vce_ring_test_ring(struct amdgpu_ring *ring);
int amdgpu_vce_ring_test_ib(struct amdgpu_ring *ring); int amdgpu_vce_ring_test_ib(struct amdgpu_ring *ring);
void amdgpu_vce_ring_begin_use(struct amdgpu_ring *ring);
void amdgpu_vce_ring_end_use(struct amdgpu_ring *ring);
#endif #endif

View File

@ -594,6 +594,8 @@ static const struct amdgpu_ring_funcs vce_v2_0_ring_funcs = {
.test_ib = amdgpu_vce_ring_test_ib, .test_ib = amdgpu_vce_ring_test_ib,
.insert_nop = amdgpu_ring_insert_nop, .insert_nop = amdgpu_ring_insert_nop,
.pad_ib = amdgpu_ring_generic_pad_ib, .pad_ib = amdgpu_ring_generic_pad_ib,
.begin_use = amdgpu_vce_ring_begin_use,
.end_use = amdgpu_vce_ring_end_use,
}; };
static void vce_v2_0_set_ring_funcs(struct amdgpu_device *adev) static void vce_v2_0_set_ring_funcs(struct amdgpu_device *adev)

View File

@ -767,6 +767,8 @@ static const struct amdgpu_ring_funcs vce_v3_0_ring_funcs = {
.test_ib = amdgpu_vce_ring_test_ib, .test_ib = amdgpu_vce_ring_test_ib,
.insert_nop = amdgpu_ring_insert_nop, .insert_nop = amdgpu_ring_insert_nop,
.pad_ib = amdgpu_ring_generic_pad_ib, .pad_ib = amdgpu_ring_generic_pad_ib,
.begin_use = amdgpu_vce_ring_begin_use,
.end_use = amdgpu_vce_ring_end_use,
}; };
static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev) static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev)