blob: 54e8594d79cf2a5afba904f20d1524877b2a9972 [file] [log] [blame]
Chris Wilsonbaa5be02013-08-20 09:27:34 +01001#include <sys/stat.h>
2#include <stdlib.h>
3#include <stdio.h>
4#include <string.h>
5#include <unistd.h>
6#include <fcntl.h>
7#include <time.h>
8#include <errno.h>
9
10#include "rc6.h"
11
12int rc6_init(struct rc6 *rc6)
13{
14 struct stat st;
15 int fd;
16
17 memset(rc6, 0, sizeof(*rc6));
18
19 fd = stat("/sys/class/drm/card0/power", &st);
20 if (fd == -1)
21 return rc6->error = errno;
22
23 return 0;
24}
25
26static uint64_t file_to_u64(const char *path)
27{
28 char buf[4096];
29 int fd, len;
30
31 fd = open(path, 0);
32 if (fd < 0)
33 return 0;
34
35 len = read(fd, buf, sizeof(buf)-1);
36 close(fd);
37
38 if (len < 0)
39 return 0;
40
41 buf[len] = '\0';
42
43 return strtoull(buf, 0, 0);
44}
45
46static uint64_t clock_ms_to_u64(void)
47{
48 struct timespec tv;
49
50 if (clock_gettime(CLOCK_MONOTONIC, &tv) < 0)
51 return 0;
52
53 return (uint64_t)tv.tv_sec * 1000 + tv.tv_nsec / 10000000;
54}
55
56int rc6_update(struct rc6 *rc6)
57{
58 struct rc6_stat *s = &rc6->stat[rc6->count++&1];
59 struct rc6_stat *d = &rc6->stat[rc6->count&1];
60 uint64_t d_time, d_rc6, d_rc6p, d_rc6pp;
61 struct stat st;
62
63 if (rc6->error)
64 return rc6->error;
65
66 if (stat("/sys/class/drm/card0/power", &st) < 0)
67 return rc6->error = errno;
68
69 if (stat("/sys/class/drm/card0/power/rc6_residency_ms", &st) < 0)
70 return ENOENT;
71
72 s->rc6_residency = file_to_u64("/sys/class/drm/card0/power/rc6_residency_ms");
73 s->rc6p_residency = file_to_u64("/sys/class/drm/card0/power/rc6p_residency_ms");
74 s->rc6pp_residency = file_to_u64("/sys/class/drm/card0/power/rc6pp_residency_ms");
75 s->timestamp = clock_ms_to_u64();
76
77 if (rc6->count == 1)
78 return EAGAIN;
79
80 d_time = s->timestamp - d->timestamp;
81
82 d_rc6 = s->rc6_residency - d->rc6_residency;
83 rc6->rc6 = 100 * d_rc6 / d_time;
84
85 d_rc6p = s->rc6p_residency - d->rc6p_residency;
86 rc6->rc6p = 100 * d_rc6p / d_time;
87
88 d_rc6pp = s->rc6pp_residency - d->rc6pp_residency;
89 rc6->rc6pp = 100 * d_rc6pp / d_time;
90
91 rc6->rc6_combined = 100 * (d_rc6 + d_rc6p + d_rc6pp) / d_time;
92 return 0;
93}