From: Marco A Benatto <marco.antonio....@gmail.com>

Adding a Frames Per Second estimation logic on UVD handles
when it has being used. This estimation is per handle basis
and will help on DPM profile calculation.

v2 (chk): fix timestamp type, move functions around and
          cleanup code a bit.

Signed-off-by: Marco A Benatto <marco.antonio.780 at gmail.com>
Signed-off-by: Christian K?nig <christian.koenig at amd.com>
---
 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

Reply via email to