• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &reg_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