Signed-off-by: Marco A Benatto <marco.antonio.780@xxxxxxxxx>
Signed-off-by: Christian König <christian.koenig@xxxxxxx>
---
drivers/gpu/drm/radeon/radeon.h | 10 ++++++
drivers/gpu/drm/radeon/radeon_uvd.c | 64
+++++++++++++++++++++++++++++++++----
2 files changed, 68 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon.h
b/drivers/gpu/drm/radeon/radeon.h
index 9e1732e..e92f6cb 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1617,6 +1617,15 @@ int radeon_pm_get_type_index(struct
radeon_device
*rdev,
#define RADEON_UVD_STACK_SIZE (1024*1024)
#define RADEON_UVD_HEAP_SIZE (1024*1024)
+#define RADEON_UVD_FPS_EVENTS_MAX 8
+#define RADEON_UVD_DEFAULT_FPS 60
+
+struct radeon_uvd_fps {
+ uint64_t timestamp;
+ uint8_t event_index;
+ uint8_t events[RADEON_UVD_FPS_EVENTS_MAX];
+};
+
struct radeon_uvd {
struct radeon_bo *vcpu_bo;
void *cpu_addr;
@@ -1626,6 +1635,7 @@ struct radeon_uvd {
struct drm_file *filp[RADEON_MAX_UVD_HANDLES];
unsigned img_size[RADEON_MAX_UVD_HANDLES];
struct delayed_work idle_work;
+ struct radeon_uvd_fps fps_info[RADEON_MAX_UVD_HANDLES];
};
int radeon_uvd_init(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c
b/drivers/gpu/drm/radeon/radeon_uvd.c
index 6bf55ec..ef5667a 100644
--- a/drivers/gpu/drm/radeon/radeon_uvd.c
+++ b/drivers/gpu/drm/radeon/radeon_uvd.c
@@ -237,6 +237,51 @@ void radeon_uvd_force_into_uvd_segment(struct
radeon_bo *rbo)
rbo->placement.lpfn = (256 * 1024 * 1024) >> PAGE_SHIFT;
}
+static void radeon_uvd_fps_clear_events(struct radeon_device *rdev,
int
idx)
+{
+ struct radeon_uvd_fps *fps = &rdev->uvd.fps_info[idx];
+ unsigned i;
+
+ fps->timestamp = jiffies_64;
+ fps->event_index = 0;
+ for (i = 0; i < RADEON_UVD_FPS_EVENTS_MAX; i++)
+ fps->events[i] = 0;
+}
+
+static void radeon_uvd_fps_note_event(struct radeon_device *rdev,
int
idx)
+{
+ struct radeon_uvd_fps *fps = &rdev->uvd.fps_info[idx];
+ uint64_t timestamp = jiffies_64;
+ unsigned rate = 0;
+
+ uint8_t index = fps->event_index++;
+ fps->event_index %= RADEON_UVD_FPS_EVENTS_MAX;
+
+ rate = div64_u64(HZ, max(timestamp - fps->timestamp, 1ULL));
+
+ fps->timestamp = timestamp;
+ fps->events[index] = min(rate, 120u);
+}
+
+static unsigned radeon_uvd_estimate_fps(struct radeon_device *rdev,
int
idx)
+{
+ struct radeon_uvd_fps *fps = &rdev->uvd.fps_info[idx];
+ unsigned i, valid = 0, count = 0;
+
+ for (i = 0; i < RADEON_UVD_FPS_EVENTS_MAX; i++) {
+ /* We should ignore zero values */
+ if (fps->events[i] != 0) {
+ count += fps->events[i];
+ valid++;
+ }
+ }
+
+ if (valid > 0)
+ return count / valid;
+ else
+ return RADEON_UVD_DEFAULT_FPS;
+}
+
void radeon_uvd_free_handles(struct radeon_device *rdev, struct
drm_file *filp)
{
int i, r;
@@ -419,8 +464,10 @@ static int radeon_uvd_cs_msg(struct
radeon_cs_parser
*p, struct radeon_bo *bo,
/* create or decode, validate the handle */
for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
- if (atomic_read(&p->rdev->uvd.handles[i]) == handle)
+ if (atomic_read(&p->rdev->uvd.handles[i]) == handle)
{
+ radeon_uvd_fps_note_event(p->rdev, i);
return 0;
+ }
}
/* handle not found try to alloc a new one */
@@ -428,6 +475,7 @@ static int radeon_uvd_cs_msg(struct
radeon_cs_parser
*p, struct radeon_bo *bo,
if (!atomic_cmpxchg(&p->rdev->uvd.handles[i], 0,
handle)) {
p->rdev->uvd.filp[i] = p->filp;
p->rdev->uvd.img_size[i] = img_size;
+ radeon_uvd_fps_clear_events(p->rdev, i);
return 0;
}
}
@@ -763,7 +811,7 @@ int radeon_uvd_get_destroy_msg(struct
radeon_device
*rdev, int ring,
static void radeon_uvd_count_handles(struct radeon_device *rdev,
unsigned *sd, unsigned *hd)
{
- unsigned i;
+ unsigned i, fps_rate = 0;
*sd = 0;
*hd = 0;
@@ -772,10 +820,13 @@ static void radeon_uvd_count_handles(struct
radeon_device *rdev,
if (!atomic_read(&rdev->uvd.handles[i]))
continue;
- if (rdev->uvd.img_size[i] >= 720*576)
- ++(*hd);
- else
- ++(*sd);
+ fps_rate = radeon_uvd_estimate_fps(rdev, i);
+
+ if (rdev->uvd.img_size[i] >= 720*576) {
+ (*hd) += fps_rate > 30 ? 1 : 2;
+ } else {
+ (*sd) += fps_rate > 30 ? 1 : 2;
+ }
}
}
@@ -805,6 +856,7 @@ void radeon_uvd_note_usage(struct radeon_device
*rdev)
set_clocks &= schedule_delayed_work(&rdev->uvd.idle_work,
msecs_to_jiffies(UVD_IDLE_TIMEOUT_MS));
+
if ((rdev->pm.pm_method == PM_METHOD_DPM) &&
rdev->pm.dpm_enabled) {
unsigned hd = 0, sd = 0;
radeon_uvd_count_handles(rdev, &sd, &hd);
--
1.9.1