blob: f94a0e116072a5fa4cbf392af4afa065085dcc07 [file] [log] [blame]
Chris Wilson9579e542016-05-23 21:56:01 +01001/*
2 * Copyright © 2013 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 */
24
25#define _GNU_SOURCE
26#include <sched.h>
27
28#include "igt.h"
Chris Wilsonc74e0712016-05-24 16:24:15 +010029#include "igt_stats.h"
Chris Wilson9579e542016-05-23 21:56:01 +010030
Tomeu Vizoso047c9992016-06-07 10:18:34 +020031#if defined(__x86_64__) || defined(__i386__)
32#define cpu_relax() __builtin_ia32_pause()
33#else
34#define cpu_relax() asm volatile("": : :"memory")
35#endif
36
Chris Wilson9579e542016-05-23 21:56:01 +010037IGT_TEST_DESCRIPTION("Stress legacy cursor ioctl");
38
39struct data {
40 int fd;
Chris Wilsoncce2ff02016-05-25 08:34:25 +010041 drmModeRes *resources;
Chris Wilson9579e542016-05-23 21:56:01 +010042};
43
44static uint32_t state = 0x12345678;
45
46static uint32_t
47hars_petruska_f54_1_random (void)
48{
49#define rol(x,k) ((x << k) | (x >> (32-k)))
50 return state = (state ^ rol (state, 5) ^ rol (state, 24)) + 0x37798849;
51#undef rol
52}
53
Chris Wilsondab6b6b2016-05-24 16:14:32 +010054static void stress(struct data *data,
Chris Wilsoncce2ff02016-05-25 08:34:25 +010055 uint32_t *crtc_id, unsigned num_crtcs,
56 int num_children, unsigned mode,
57 int timeout)
Chris Wilson9579e542016-05-23 21:56:01 +010058{
Chris Wilson9579e542016-05-23 21:56:01 +010059 struct drm_mode_cursor arg;
Chris Wilsonc74e0712016-05-24 16:24:15 +010060 uint64_t *results;
Chris Wilsonf5d370c2016-06-04 21:25:17 +010061 bool torture;
Chris Wilson9579e542016-05-23 21:56:01 +010062 int n;
63
Chris Wilsonf5d370c2016-06-04 21:25:17 +010064 torture = false;
65 if (num_children < 0) {
66 torture = true;
67 num_children = -num_children;
68 }
69
Chris Wilsonc74e0712016-05-24 16:24:15 +010070 results = mmap(NULL, 4096, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
71 igt_assert(results != MAP_FAILED);
72
Chris Wilson9579e542016-05-23 21:56:01 +010073 memset(&arg, 0, sizeof(arg));
74 arg.flags = DRM_MODE_CURSOR_BO;
75 arg.crtc_id = 0;
76 arg.width = 64;
77 arg.height = 64;
78 arg.handle = gem_create(data->fd, 4*64*64);
79
Chris Wilsoncce2ff02016-05-25 08:34:25 +010080 for (n = 0; n < num_crtcs; n++) {
81 arg.crtc_id = crtc_id[n];
Chris Wilson9579e542016-05-23 21:56:01 +010082 drmIoctl(data->fd, DRM_IOCTL_MODE_CURSOR, &arg);
Chris Wilsoncce2ff02016-05-25 08:34:25 +010083 }
Chris Wilson9579e542016-05-23 21:56:01 +010084
85 arg.flags = mode;
Chris Wilsondab6b6b2016-05-24 16:14:32 +010086 igt_fork(child, num_children) {
Chris Wilson9579e542016-05-23 21:56:01 +010087 struct sched_param rt = {.sched_priority = 99 };
88 cpu_set_t allowed;
89 unsigned long count = 0;
90
91 sched_setscheduler(getpid(), SCHED_RR, &rt);
92
93 CPU_ZERO(&allowed);
94 CPU_SET(child, &allowed);
95 sched_setaffinity(getpid(), sizeof(cpu_set_t), &allowed);
96
Chris Wilsonbd860da2016-05-24 08:31:22 +010097 state ^= child;
Chris Wilson9579e542016-05-23 21:56:01 +010098 igt_until_timeout(timeout) {
Chris Wilsoncce2ff02016-05-25 08:34:25 +010099 arg.crtc_id = crtc_id[hars_petruska_f54_1_random() % num_crtcs];
Chris Wilson9579e542016-05-23 21:56:01 +0100100 do_ioctl(data->fd, DRM_IOCTL_MODE_CURSOR, &arg);
101 count++;
102 }
103
Chris Wilsonc74e0712016-05-24 16:24:15 +0100104 igt_debug("[%d] count=%lu\n", child, count);
105 results[child] = count;
Chris Wilson9579e542016-05-23 21:56:01 +0100106 }
Chris Wilsonf5d370c2016-06-04 21:25:17 +0100107 if (torture) {
108 igt_fork(child, num_children) {
109 struct sched_param rt = {.sched_priority = 1 };
110 cpu_set_t allowed;
111 unsigned long long count = 0;
112
113 sched_setscheduler(getpid(), SCHED_RR, &rt);
114
115 CPU_ZERO(&allowed);
116 CPU_SET(child, &allowed);
117 sched_setaffinity(getpid(), sizeof(cpu_set_t), &allowed);
118 igt_until_timeout(timeout) {
119 count++;
Tomeu Vizoso047c9992016-06-07 10:18:34 +0200120 cpu_relax();
Chris Wilsonf5d370c2016-06-04 21:25:17 +0100121 }
122 igt_debug("[hog:%d] count=%llu\n", child, count);
123 }
124 }
Chris Wilson9579e542016-05-23 21:56:01 +0100125 igt_waitchildren();
126
Chris Wilsonc74e0712016-05-24 16:24:15 +0100127 if (num_children > 1) {
128 igt_stats_t stats;
129
130 igt_stats_init_with_size(&stats, num_children);
131 results[num_children] = 0;
132 for (int child = 0; child < num_children; child++) {
133 igt_stats_push(&stats, results[child]);
134 results[num_children] += results[child];
135 }
136 igt_info("Total updates %llu (median of %d processes is %.2f)\n",
137 (long long)results[num_children],
138 num_children,
139 igt_stats_get_median(&stats));
140 igt_stats_fini(&stats);
141 } else {
142 igt_info("Total updates %llu\n", (long long)results[0]);
143 }
144
Chris Wilson9579e542016-05-23 21:56:01 +0100145 gem_close(data->fd, arg.handle);
Chris Wilsonc74e0712016-05-24 16:24:15 +0100146 munmap(results, 4096);
Chris Wilson9579e542016-05-23 21:56:01 +0100147}
148
Chris Wilson162d4562016-06-22 15:41:23 +0100149static bool set_fb_on_crtc(struct data *data, int pipe, struct igt_fb *fb_info)
150{
151 struct drm_mode_modeinfo *modes = malloc(4096*sizeof(*modes));
152 uint32_t encoders[32];
153
154 for (int o = 0; o < data->resources->count_connectors; o++) {
155 struct drm_mode_get_connector conn;
156 struct drm_mode_crtc set;
157 int e, m;
158
159 memset(&conn, 0, sizeof(conn));
160 conn.connector_id = data->resources->connectors[o];
161 conn.count_modes = 4096;
162 conn.modes_ptr = (uintptr_t)modes;
163 conn.count_encoders = 32;
164 conn.encoders_ptr = (uintptr_t)encoders;
165
166 drmIoctl(data->fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn);
167
168 for (e = 0; e < conn.count_encoders; e++) {
169 struct drm_mode_get_encoder enc;
170
171 memset(&enc, 0, sizeof(enc));
172 enc.encoder_id = encoders[e];
173 drmIoctl(data->fd, DRM_IOCTL_MODE_GETENCODER, &enc);
174 if (enc.possible_crtcs & (1 << pipe))
175 break;
176 }
177 if (e == conn.count_encoders)
178 continue;
179
180 for (m = 0; m < conn.count_modes; m++) {
181 if (modes[m].hdisplay == fb_info->width &&
182 modes[m].vdisplay == fb_info->height)
183 break;
184 }
185 if (m == conn.count_modes)
186 continue;
187
188 memset(&set, 0, sizeof(set));
189 set.crtc_id = data->resources->crtcs[pipe];
190 set.fb_id = fb_info->fb_id;
191 set.set_connectors_ptr = (uintptr_t)&conn.connector_id;
192 set.count_connectors = 1;
193 set.mode = modes[m];
194 set.mode_valid = 1;
195 if (drmIoctl(data->fd, DRM_IOCTL_MODE_SETCRTC, &set) == 0)
196 return true;
197 }
198
199 return false;
200}
201
202static void flip(struct data *data,
203 int cursor_pipe, int flip_pipe,
204 int timeout)
205{
206 struct drm_mode_cursor arg;
207 uint64_t *results;
208 struct igt_fb fb_info;
209 uint32_t fb_id;
210
211 results = mmap(NULL, 4096, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
212 igt_assert(results != MAP_FAILED);
213
214 memset(&arg, 0, sizeof(arg));
215 arg.flags = DRM_MODE_CURSOR_BO;
216 arg.crtc_id = data->resources->crtcs[cursor_pipe];
217 arg.width = 64;
218 arg.height = 64;
219 arg.handle = gem_create(data->fd, 4*64*64);
220
221 drmIoctl(data->fd, DRM_IOCTL_MODE_CURSOR, &arg);
222
223 fb_id = igt_create_fb(data->fd, 1024, 768, DRM_FORMAT_XRGB8888,
224 I915_TILING_NONE, &fb_info);
225 igt_require(set_fb_on_crtc(data, flip_pipe, &fb_info));
226
227 arg.flags = DRM_MODE_CURSOR_MOVE;
228 igt_fork(child, 1) {
229 unsigned long count = 0;
230
231 igt_until_timeout(timeout) {
232 do_ioctl(data->fd, DRM_IOCTL_MODE_CURSOR, &arg);
233 count++;
234 }
235
236 igt_debug("cursor count=%lu\n", count);
237 results[0] = count;
238 }
239 igt_fork(child, 1) {
240 unsigned long count = 0;
241 unsigned crtc = data->resources->crtcs[flip_pipe];
242
243 igt_until_timeout(timeout) {
244 char buf[128];
245 drmModePageFlip(data->fd, crtc, fb_id,
246 DRM_MODE_PAGE_FLIP_EVENT,
247 NULL);
248 read(data->fd, buf, sizeof(buf));
249 count++;
250 }
251
252 igt_debug("flip count=%lu\n", count);
253 results[1] = count;
254 }
255 igt_waitchildren();
256
257 gem_close(data->fd, arg.handle);
258 munmap(results, 4096);
259}
260
261static inline uint32_t pipe_select(int pipe)
262{
263 if (pipe > 1)
264 return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
265 else if (pipe > 0)
266 return DRM_VBLANK_SECONDARY;
267 else
268 return 0;
269}
270
271static unsigned get_vblank(int fd, int pipe, unsigned flags)
272{
273 union drm_wait_vblank vbl;
274
275 memset(&vbl, 0, sizeof(vbl));
276 vbl.request.type = DRM_VBLANK_RELATIVE | pipe_select(pipe) | flags;
277 if (drmIoctl(fd, DRM_IOCTL_WAIT_VBLANK, &vbl))
278 return 0;
279
280 return vbl.reply.sequence;
281}
282
283static void basic_flip(struct data *data)
284{
285 struct drm_mode_cursor arg;
286 struct igt_fb fb_info;
287 unsigned vblank_start;
288 int target;
289 char buf[128];
290 uint32_t fb_id;
291
292 memset(&arg, 0, sizeof(arg));
293 arg.flags = DRM_MODE_CURSOR_BO;
294 arg.crtc_id = data->resources->crtcs[0];
295 arg.width = 64;
296 arg.height = 64;
297 arg.handle = gem_create(data->fd, 4*64*64);
298
299 drmIoctl(data->fd, DRM_IOCTL_MODE_CURSOR, &arg);
300 arg.flags = DRM_MODE_CURSOR_MOVE;
301
302 fb_id = igt_create_fb(data->fd, 1024, 768, DRM_FORMAT_XRGB8888,
303 I915_TILING_NONE, &fb_info);
304 igt_require(set_fb_on_crtc(data, 0, &fb_info));
305
306 target = 4096;
307 do {
308 vblank_start = get_vblank(data->fd, 0, DRM_VBLANK_NEXTONMISS);
309 igt_assert_eq(get_vblank(data->fd, 0, 0), vblank_start);
310 for (int n = 0; n < target; n++)
311 do_ioctl(data->fd, DRM_IOCTL_MODE_CURSOR, &arg);
312 target /= 2;
313 if (get_vblank(data->fd, 0, 0) == vblank_start)
314 break;
315 } while (target);
316 igt_require(target > 1);
317
318 igt_debug("Using a target of %d cursor updates per half-vblank\n",
319 target);
320
321 vblank_start = get_vblank(data->fd, 0, DRM_VBLANK_NEXTONMISS);
322 igt_assert_eq(get_vblank(data->fd, 0, 0), vblank_start);
323 for (int n = 0; n < target; n++)
324 do_ioctl(data->fd, DRM_IOCTL_MODE_CURSOR, &arg);
325 igt_assert_eq(get_vblank(data->fd, 0, 0), vblank_start);
326
327 /* Start with a synchronous flip to align with the vblank */
328 drmModePageFlip(data->fd, arg.crtc_id, fb_id, 0, NULL);
329 do_ioctl(data->fd, DRM_IOCTL_MODE_CURSOR, &arg);
330 vblank_start = get_vblank(data->fd, 0, 0);
331
332 /* Schedule a nonblocking flip for the next vblank */
333 drmModePageFlip(data->fd, arg.crtc_id, fb_id,
334 DRM_MODE_PAGE_FLIP_EVENT, NULL);
335
336 igt_assert_eq(get_vblank(data->fd, 0, 0), vblank_start);
337 for (int n = 0; n < target; n++)
338 do_ioctl(data->fd, DRM_IOCTL_MODE_CURSOR, &arg);
339 igt_assert_eq(get_vblank(data->fd, 0, 0), vblank_start);
340
341 igt_set_timeout(1, "Stuck page flip");
342 read(data->fd, buf, sizeof(buf));
343 igt_assert_eq(get_vblank(data->fd, 0, 0), vblank_start + 1);
344 igt_reset_timeout();
345
346 igt_remove_fb(data->fd, &fb_info);
347}
348
Chris Wilson9579e542016-05-23 21:56:01 +0100349igt_main
350{
Chris Wilsondab6b6b2016-05-24 16:14:32 +0100351 const int ncpus = sysconf(_SC_NPROCESSORS_ONLN);
Chris Wilson9579e542016-05-23 21:56:01 +0100352 struct data data = { .fd = -1 };
353
354 igt_skip_on_simulation();
355
356 igt_fixture {
357 data.fd = drm_open_driver_master(DRIVER_INTEL);
358 kmstest_set_vt_graphics_mode();
Chris Wilsoncce2ff02016-05-25 08:34:25 +0100359
360 data.resources = drmModeGetResources(data.fd);
361 igt_assert(data.resources);
Chris Wilson9579e542016-05-23 21:56:01 +0100362 }
363
Chris Wilsoncce2ff02016-05-25 08:34:25 +0100364 igt_subtest_group {
365 for (int n = 0; n < 26; n++) {
Chris Wilson04b8f0e2016-05-25 14:53:34 +0100366 uint32_t *crtcs = NULL;
Chris Wilsondab6b6b2016-05-24 16:14:32 +0100367
Chris Wilsoncce2ff02016-05-25 08:34:25 +0100368 errno = 0;
Chris Wilson04b8f0e2016-05-25 14:53:34 +0100369 igt_fixture {
Chris Wilsoncce2ff02016-05-25 08:34:25 +0100370 igt_skip_on(n >= data.resources->count_crtcs);
Chris Wilson04b8f0e2016-05-25 14:53:34 +0100371 crtcs = &data.resources->crtcs[n];
372 }
Chris Wilsoncce2ff02016-05-25 08:34:25 +0100373
374 igt_subtest_f("single-%c-bo", 'A' + n)
375 stress(&data, crtcs, 1, 1, DRM_MODE_CURSOR_BO, 20);
376 igt_subtest_f("single-%c-move", 'A' + n)
377 stress(&data, crtcs, 1, 1, DRM_MODE_CURSOR_MOVE, 20);
378
379 igt_subtest_f("forked-%c-bo", 'A' + n)
380 stress(&data, crtcs, 1, ncpus, DRM_MODE_CURSOR_BO, 20);
381 igt_subtest_f("forked-%c-move", 'A' + n)
382 stress(&data, crtcs, 1, ncpus, DRM_MODE_CURSOR_MOVE, 20);
Chris Wilsonf5d370c2016-06-04 21:25:17 +0100383
384 igt_subtest_f("torture-%c-bo", 'A' + n)
385 stress(&data, crtcs, 1, -ncpus, DRM_MODE_CURSOR_BO, 20);
386 igt_subtest_f("torture-%c-move", 'A' + n)
387 stress(&data, crtcs, 1, -ncpus, DRM_MODE_CURSOR_MOVE, 20);
Chris Wilsoncce2ff02016-05-25 08:34:25 +0100388 }
389 }
390
391 igt_subtest("single-all-bo")
392 stress(&data,
393 data.resources->crtcs, data.resources->count_crtcs,
394 1, DRM_MODE_CURSOR_BO, 20);
395 igt_subtest("single-all-move")
396 stress(&data,
397 data.resources->crtcs, data.resources->count_crtcs,
398 1, DRM_MODE_CURSOR_MOVE, 20);
399
400 igt_subtest("forked-all-bo")
401 stress(&data,
402 data.resources->crtcs, data.resources->count_crtcs,
403 ncpus, DRM_MODE_CURSOR_BO, 20);
404 igt_subtest("forked-all-move")
405 stress(&data,
406 data.resources->crtcs, data.resources->count_crtcs,
407 ncpus, DRM_MODE_CURSOR_MOVE, 20);
Chris Wilson9579e542016-05-23 21:56:01 +0100408
Chris Wilsonf5d370c2016-06-04 21:25:17 +0100409 igt_subtest("torture-all-bo")
410 stress(&data,
411 data.resources->crtcs, data.resources->count_crtcs,
412 -ncpus, DRM_MODE_CURSOR_BO, 20);
413 igt_subtest("torture-all-move")
414 stress(&data,
415 data.resources->crtcs, data.resources->count_crtcs,
416 -ncpus, DRM_MODE_CURSOR_MOVE, 20);
417
Chris Wilson162d4562016-06-22 15:41:23 +0100418 igt_subtest_group {
419 igt_subtest("basic-cursor-vs-flip")
420 basic_flip(&data);
421
422 igt_subtest("cursorA-vs-flipA")
423 flip(&data, 0, 0, 10);
424 igt_subtest("cursorA-vs-flipB")
425 flip(&data, 0, 1, 10);
426 igt_subtest("cursorB-vs-flipA")
427 flip(&data, 1, 0, 10);
428 igt_subtest("cursorB-vs-flipB")
429 flip(&data, 1, 1, 10);
430 }
431
Chris Wilson9579e542016-05-23 21:56:01 +0100432 igt_fixture {
Chris Wilsoncce2ff02016-05-25 08:34:25 +0100433 drmModeFreeResources(data.resources);
Chris Wilson9579e542016-05-23 21:56:01 +0100434 }
435}