1 /*
2 * Copyright © 2012 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 * Authors:
24 * Ben Widawsky <ben@bwidawsk.net>
25 *
26 */
27
28 #include "igt.h"
29 #include <stdio.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <sys/utsname.h>
33 #include <time.h>
34
35
36 static bool is_x86_64;
37 static bool has_proper_timestamp;
38
39 struct local_drm_i915_reg_read {
40 __u64 offset;
41 __u64 val; /* Return value */
42 };
43
44 #define REG_READ_IOCTL DRM_IOWR(DRM_COMMAND_BASE + 0x31, struct local_drm_i915_reg_read)
45
46 #define RENDER_RING_TIMESTAMP 0x2358
47
read_register(int fd,uint64_t offset,uint64_t * val)48 static int read_register(int fd, uint64_t offset, uint64_t * val)
49 {
50 int ret = 0;
51 struct local_drm_i915_reg_read reg_read;
52 reg_read.offset = offset;
53
54 if (drmIoctl(fd, REG_READ_IOCTL, ®_read))
55 ret = -errno;
56
57 *val = reg_read.val;
58
59 return ret;
60 }
61
check_kernel_x86_64(void)62 static bool check_kernel_x86_64(void)
63 {
64 int ret;
65 struct utsname uts;
66
67 ret = uname(&uts);
68 igt_assert_eq(ret, 0);
69
70 if (!strcmp(uts.machine, "x86_64"))
71 return true;
72
73 return false;
74 }
75
check_timestamp(int fd)76 static bool check_timestamp(int fd)
77 {
78 int ret;
79 uint64_t val;
80
81 ret = read_register(fd, RENDER_RING_TIMESTAMP | 1, &val);
82
83 return ret == 0;
84 }
85
timer_query(int fd,uint64_t * val)86 static int timer_query(int fd, uint64_t * val)
87 {
88 uint64_t offset;
89 int ret;
90
91 offset = RENDER_RING_TIMESTAMP;
92 if (has_proper_timestamp)
93 offset |= 1;
94
95 ret = read_register(fd, offset, val);
96
97 /*
98 * When reading the timestamp register with single 64b read, we are observing
99 * invalid values on x86_64:
100 *
101 * [f = valid counter value | X = garbage]
102 *
103 * i386: 0x0000000fffffffff
104 * x86_64: 0xffffffffXXXXXXXX
105 *
106 * In the absence of a corrected register read ioctl, attempt
107 * to fix up the return value to be vaguely useful.
108 */
109
110 if (is_x86_64 && !has_proper_timestamp)
111 *val >>= 32;
112
113 return ret;
114 }
115
test_timestamp_moving(int fd)116 static void test_timestamp_moving(int fd)
117 {
118 uint64_t first_val, second_val;
119
120 igt_fail_on(timer_query(fd, &first_val) != 0);
121 sleep(1);
122 igt_fail_on(timer_query(fd, &second_val) != 0);
123 igt_assert(second_val != first_val);
124 }
125
test_timestamp_monotonic(int fd)126 static void test_timestamp_monotonic(int fd)
127 {
128 uint64_t first_val, second_val;
129 time_t start;
130 bool retry = true;
131
132 igt_fail_on(timer_query(fd, &first_val) != 0);
133 time(&start);
134 do {
135 retry:
136 igt_fail_on(timer_query(fd, &second_val) != 0);
137 if (second_val < first_val && retry) {
138 /* We may hit timestamp overflow once */
139 retry = false;
140 first_val = second_val;
141 goto retry;
142 }
143 igt_assert(second_val >= first_val);
144 } while(difftime(time(NULL), start) < 5);
145
146 }
147
148 igt_main
149 {
150 uint64_t val = 0;
151 int fd = -1;
152
153 igt_fixture {
154 fd = drm_open_driver(DRIVER_INTEL);
155 is_x86_64 = check_kernel_x86_64();
156 has_proper_timestamp = check_timestamp(fd);
157 }
158
159 igt_subtest("bad-register")
160 igt_assert_eq(read_register(fd, 0x12345678, &val), -EINVAL);
161
162 igt_subtest("timestamp-moving") {
163 igt_skip_on(timer_query(fd, &val) != 0);
164 test_timestamp_moving(fd);
165 }
166
167 igt_subtest("timestamp-monotonic") {
168 igt_skip_on(timer_query(fd, &val) != 0);
169 test_timestamp_monotonic(fd);
170 }
171
172 igt_fixture {
173 close(fd);
174 }
175 }
176