1 /*
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 #include <sched.h>
26 #include <sys/poll.h>
27 
28 #include "igt.h"
29 #include "igt_rand.h"
30 #include "igt_stats.h"
31 
32 #if defined(__x86_64__) || defined(__i386__)
33 #define cpu_relax()	__builtin_ia32_pause()
34 #else
35 #define cpu_relax()	asm volatile("": : :"memory")
36 #endif
37 
38 #ifndef DRM_CAP_CURSOR_WIDTH
39 #define DRM_CAP_CURSOR_WIDTH 0x8
40 #endif
41 
42 #ifndef DRM_CAP_CURSOR_HEIGHT
43 #define DRM_CAP_CURSOR_HEIGHT 0x9
44 #endif
45 
46 #define PAGE_SIZE	4096
47 
48 IGT_TEST_DESCRIPTION("Stress legacy cursor ioctl");
49 
50 igt_pipe_crc_t *pipe_crc;
51 
stress(igt_display_t * display,enum pipe pipe,int num_children,unsigned mode,int timeout)52 static void stress(igt_display_t *display,
53 		   enum pipe pipe, int num_children, unsigned mode,
54 		   int timeout)
55 {
56 	struct drm_mode_cursor arg;
57 	uint64_t *results;
58 	bool torture;
59 	int n;
60 	unsigned crtc_id[IGT_MAX_PIPES], num_crtcs;
61 
62 	torture = false;
63 	if (num_children < 0) {
64 		torture = true;
65 		num_children = -num_children;
66 	}
67 
68 	results = mmap(NULL, PAGE_SIZE, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
69 	igt_assert(results != MAP_FAILED);
70 
71 	memset(&arg, 0, sizeof(arg));
72 	arg.flags = DRM_MODE_CURSOR_BO;
73 	arg.crtc_id = 0;
74 	arg.width = 64;
75 	arg.height = 64;
76 	arg.handle = kmstest_dumb_create(display->drm_fd, 64, 64, 32, NULL, NULL);
77 
78 	if (pipe < 0) {
79 		num_crtcs = display->n_pipes;
80 		for_each_pipe(display, n) {
81 			arg.crtc_id = crtc_id[n] = display->pipes[n].crtc_id;
82 			do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, &arg);
83 		}
84 	} else {
85 		num_crtcs = 1;
86 		arg.crtc_id = crtc_id[0] = display->pipes[pipe].crtc_id;
87 		do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, &arg);
88 	}
89 
90 	arg.flags = mode;
91 	igt_fork(child, num_children) {
92 		struct sched_param rt = {.sched_priority = 99 };
93 		cpu_set_t allowed;
94 		unsigned long count = 0;
95 
96 		sched_setscheduler(getpid(), SCHED_RR, &rt);
97 
98 		CPU_ZERO(&allowed);
99 		CPU_SET(child, &allowed);
100 		sched_setaffinity(getpid(), sizeof(cpu_set_t), &allowed);
101 
102 		hars_petruska_f54_1_random_perturb(child);
103 		igt_until_timeout(timeout) {
104 			arg.crtc_id = crtc_id[hars_petruska_f54_1_random_unsafe() % num_crtcs];
105 			do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, &arg);
106 			count++;
107 		}
108 
109 		igt_debug("[%d] count=%lu\n", child, count);
110 		results[child] = count;
111 	}
112 	if (torture) {
113 		igt_fork(child, num_children) {
114 			struct sched_param rt = {.sched_priority = 1 };
115 			cpu_set_t allowed;
116 			unsigned long long count = 0;
117 
118 			sched_setscheduler(getpid(), SCHED_RR, &rt);
119 
120 			CPU_ZERO(&allowed);
121 			CPU_SET(child, &allowed);
122 			sched_setaffinity(getpid(), sizeof(cpu_set_t), &allowed);
123 			igt_until_timeout(timeout) {
124 				count++;
125 				cpu_relax();
126 			}
127 			igt_debug("[hog:%d] count=%llu\n", child, count);
128 		}
129 	}
130 	igt_waitchildren();
131 
132 	if (num_children > 1) {
133 		igt_stats_t stats;
134 
135 		igt_stats_init_with_size(&stats, num_children);
136 		results[num_children] = 0;
137 		for (int child = 0; child < num_children; child++) {
138 			igt_stats_push(&stats, results[child]);
139 			results[num_children] += results[child];
140 		}
141 		igt_info("Total updates %llu (median of %d processes is %.2f)\n",
142 			 (long long)results[num_children],
143 			 num_children,
144 			 igt_stats_get_median(&stats));
145 		igt_stats_fini(&stats);
146 	} else {
147 		igt_info("Total updates %llu\n", (long long)results[0]);
148 	}
149 
150 	gem_close(display->drm_fd, arg.handle);
151 	munmap(results, PAGE_SIZE);
152 }
153 
set_fb_on_crtc(igt_display_t * display,enum pipe pipe,struct igt_fb * fb_info)154 static igt_output_t *set_fb_on_crtc(igt_display_t *display, enum pipe pipe, struct igt_fb *fb_info)
155 {
156 	igt_output_t *output;
157 
158 	for_each_valid_output_on_pipe(display, pipe, output) {
159 		drmModeModeInfoPtr mode;
160 		igt_plane_t *primary;
161 
162 		if (output->pending_pipe != PIPE_NONE)
163 			continue;
164 
165 		igt_output_set_pipe(output, pipe);
166 		mode = igt_output_get_mode(output);
167 
168 		igt_create_pattern_fb(display->drm_fd,
169 			      mode->hdisplay, mode->vdisplay,
170 			      DRM_FORMAT_XRGB8888, I915_TILING_NONE, fb_info);
171 
172 		primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
173 		igt_plane_set_fb(primary, fb_info);
174 
175 		return output;
176 	}
177 
178 	return NULL;
179 }
180 
set_cursor_on_pipe(igt_display_t * display,enum pipe pipe,struct igt_fb * fb)181 static void set_cursor_on_pipe(igt_display_t *display, enum pipe pipe, struct igt_fb *fb)
182 {
183 	igt_plane_t *plane, *cursor = NULL;
184 
185 	for_each_plane_on_pipe(display, pipe, plane) {
186 		if (plane->type != DRM_PLANE_TYPE_CURSOR)
187 			continue;
188 
189 		cursor = plane;
190 		break;
191 	}
192 
193 	igt_require(cursor);
194 	igt_plane_set_fb(cursor, fb);
195 }
196 
populate_cursor_args(igt_display_t * display,enum pipe pipe,struct drm_mode_cursor * arg,struct igt_fb * fb)197 static void populate_cursor_args(igt_display_t *display, enum pipe pipe,
198 				 struct drm_mode_cursor *arg, struct igt_fb *fb)
199 {
200 	arg->crtc_id = display->pipes[pipe].crtc_id;
201 	arg->flags = DRM_MODE_CURSOR_MOVE;
202 	arg->x = 128;
203 	arg->y = 128;
204 	arg->width = fb->width;
205 	arg->height = fb->height;
206 	arg->handle = fb->gem_handle;
207 	arg[1] = *arg;
208 }
209 
find_connected_pipe(igt_display_t * display,bool second)210 static enum pipe find_connected_pipe(igt_display_t *display, bool second)
211 {
212 	enum pipe pipe, first = PIPE_NONE;
213 	igt_output_t *output;
214 	igt_output_t *first_output = NULL;
215 	bool found = false;
216 
217 	if (!second) {
218 		igt_pipe_crc_free(pipe_crc);
219 		pipe_crc = NULL;
220 
221 		/* Clear display, events will be eaten by commit.. */
222 		igt_display_reset(display);
223 	}
224 
225 	for_each_pipe_with_valid_output(display, pipe, output) {
226 		if (first == pipe || output == first_output)
227 			continue;
228 
229 		if (second) {
230 			first = pipe;
231 			first_output = output;
232 			second = false;
233 			continue;
234 		}
235 
236 		found = true;
237 		break;
238 	}
239 
240 	if (first_output)
241 		igt_require_f(found, "No second valid output found\n");
242 	else
243 		igt_require_f(found, "No valid outputs found\n");
244 
245 	return pipe;
246 }
247 
flip_nonblocking(igt_display_t * display,enum pipe pipe_id,bool atomic,struct igt_fb * fb,void * data)248 static void flip_nonblocking(igt_display_t *display, enum pipe pipe_id, bool atomic, struct igt_fb *fb, void *data)
249 {
250 	igt_pipe_t *pipe = &display->pipes[pipe_id];
251 	igt_plane_t *primary = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
252 	int ret;
253 
254 	igt_set_timeout(1, "Scheduling page flip\n");
255 	if (!atomic) {
256 		/* Schedule a nonblocking flip for the next vblank */
257 		do {
258 			ret = drmModePageFlip(display->drm_fd, pipe->crtc_id, fb->fb_id,
259 					      DRM_MODE_PAGE_FLIP_EVENT, data);
260 		} while (ret == -EBUSY);
261 	} else {
262 		igt_plane_set_fb(primary, fb);
263 		do {
264 			ret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_PAGE_FLIP_EVENT, data);
265 		} while (ret == -EBUSY);
266 	}
267 	igt_assert(!ret);
268 	igt_reset_timeout();
269 }
270 
271 enum flip_test {
272 	flip_test_legacy = 0,
273 	flip_test_varying_size,
274 	flip_test_toggle_visibility,
275 	flip_test_atomic,
276 	flip_test_atomic_transitions,
277 	flip_test_atomic_transitions_varying_size,
278 	flip_test_last = flip_test_atomic_transitions_varying_size
279 };
280 
cursor_slowpath(enum flip_test mode)281 static bool cursor_slowpath(enum flip_test mode)
282 {
283 	/* cursor moving doesn't take slowpath, everything else does. */
284 	if (mode == flip_test_legacy || mode == flip_test_atomic)
285 		return false;
286 
287 	return true;
288 }
289 
290 /*
291  * On platforms with two-stage watermark programming
292  * changing sprite visibility may require a extra vblank wait.
293  *
294  * Handle this here.
295  */
mode_requires_extra_vblank(enum flip_test mode)296 static bool mode_requires_extra_vblank(enum flip_test mode)
297 {
298 	if (mode == flip_test_atomic_transitions ||
299 	    mode == flip_test_atomic_transitions_varying_size)
300 		return true;
301 
302 	return false;
303 }
304 
transition_nonblocking(igt_display_t * display,enum pipe pipe_id,struct igt_fb * prim_fb,struct igt_fb * argb_fb,bool hide_sprite)305 static void transition_nonblocking(igt_display_t *display, enum pipe pipe_id,
306 				   struct igt_fb *prim_fb, struct igt_fb *argb_fb,
307 				   bool hide_sprite)
308 {
309 	igt_pipe_t *pipe = &display->pipes[pipe_id];
310 	igt_plane_t *primary = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
311 	igt_plane_t *sprite = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_OVERLAY);
312 
313 	if (hide_sprite) {
314 		igt_plane_set_fb(primary, prim_fb);
315 		igt_plane_set_fb(sprite, NULL);
316 	} else {
317 		int ret;
318 
319 		igt_plane_set_fb(primary, NULL);
320 		igt_plane_set_fb(sprite, argb_fb);
321 
322 		ret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_PAGE_FLIP_EVENT, display);
323 		if (!ret)
324 			return;
325 
326 		igt_assert(ret == -EINVAL);
327 
328 		igt_plane_set_fb(sprite, prim_fb);
329 	}
330 	igt_display_commit_atomic(display, DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_PAGE_FLIP_EVENT, display);
331 }
332 
prepare_flip_test(igt_display_t * display,enum flip_test mode,enum pipe flip_pipe,enum pipe cursor_pipe,struct drm_mode_cursor * arg,const struct igt_fb * prim_fb,struct igt_fb * argb_fb,struct igt_fb * cursor_fb2)333 static void prepare_flip_test(igt_display_t *display,
334 			      enum flip_test mode,
335 			      enum pipe flip_pipe,
336 			      enum pipe cursor_pipe,
337 			      struct drm_mode_cursor *arg,
338 			      const struct igt_fb *prim_fb,
339 			      struct igt_fb *argb_fb,
340 			      struct igt_fb *cursor_fb2)
341 {
342 	argb_fb->gem_handle = 0;
343 	cursor_fb2->gem_handle = 0;
344 
345 	if (mode == flip_test_varying_size ||
346 	    mode == flip_test_atomic_transitions_varying_size) {
347 		uint64_t width, height;
348 
349 		do_or_die(drmGetCap(display->drm_fd, DRM_CAP_CURSOR_WIDTH, &width));
350 		do_or_die(drmGetCap(display->drm_fd, DRM_CAP_CURSOR_HEIGHT, &height));
351 
352 		igt_skip_on(width <= 64 && height <= 64);
353 		igt_create_color_fb(display->drm_fd, width, height,
354 				    DRM_FORMAT_ARGB8888, 0, 1., 0., .7, cursor_fb2);
355 
356 		arg[0].flags = arg[1].flags = DRM_MODE_CURSOR_BO;
357 		arg[1].handle = cursor_fb2->gem_handle;
358 		arg[1].width = width;
359 		arg[1].height = height;
360 	}
361 
362 	if (mode == flip_test_legacy ||
363 	    mode == flip_test_atomic) {
364 		arg[1].x = 192;
365 		arg[1].y = 192;
366 	}
367 
368 	if (mode == flip_test_toggle_visibility) {
369 		arg[0].flags = arg[1].flags = DRM_MODE_CURSOR_BO;
370 		arg[1].handle = 0;
371 		arg[1].width = arg[1].height = 0;
372 	}
373 
374 	if (mode == flip_test_atomic_transitions ||
375 	    mode == flip_test_atomic_transitions_varying_size) {
376 		igt_require(display->pipes[flip_pipe].n_planes > 1 &&
377 		            display->pipes[flip_pipe].planes[1].type != DRM_PLANE_TYPE_CURSOR);
378 
379 		igt_create_color_pattern_fb(display->drm_fd, prim_fb->width, prim_fb->height,
380 					    DRM_FORMAT_ARGB8888, 0, .1, .1, .1, argb_fb);
381 	}
382 }
383 
flip(igt_display_t * display,int cursor_pipe,int flip_pipe,int timeout,enum flip_test mode)384 static void flip(igt_display_t *display,
385 		int cursor_pipe, int flip_pipe,
386 		int timeout, enum flip_test mode)
387 {
388 	struct drm_mode_cursor arg[2];
389 	uint64_t *results;
390 	struct igt_fb fb_info, fb_info2, argb_fb, cursor_fb, cursor_fb2;
391 
392 	results = mmap(NULL, PAGE_SIZE, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
393 	igt_assert(results != MAP_FAILED);
394 
395 	flip_pipe = find_connected_pipe(display, !!flip_pipe);
396 	cursor_pipe = find_connected_pipe(display, !!cursor_pipe);
397 
398 	igt_info("Using pipe %s for page flip, pipe %s for cursor\n",
399 		  kmstest_pipe_name(flip_pipe), kmstest_pipe_name(cursor_pipe));
400 
401 	if (mode >= flip_test_atomic)
402 		igt_require(display->is_atomic);
403 
404 	igt_require(set_fb_on_crtc(display, flip_pipe, &fb_info));
405 	if (flip_pipe != cursor_pipe)
406 		igt_require(set_fb_on_crtc(display, cursor_pipe, &fb_info2));
407 
408 	igt_create_color_fb(display->drm_fd, fb_info.width, fb_info.height, DRM_FORMAT_ARGB8888, 0, .5, .5, .5, &cursor_fb);
409 
410 	igt_create_color_fb(display->drm_fd, 64, 64, DRM_FORMAT_ARGB8888, 0, 1., 1., 1., &cursor_fb);
411 	set_cursor_on_pipe(display, cursor_pipe, &cursor_fb);
412 	populate_cursor_args(display, cursor_pipe, arg, &cursor_fb);
413 
414 	prepare_flip_test(display, mode, flip_pipe, cursor_pipe, arg, &fb_info, &argb_fb, &cursor_fb2);
415 
416 	igt_display_commit2(display, display->is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY);
417 
418 	igt_fork(child, 1) {
419 		unsigned long count = 0;
420 
421 		igt_until_timeout(timeout) {
422 			do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, &arg[(count & 64)/64]);
423 			count++;
424 		}
425 
426 		igt_debug("cursor count=%lu\n", count);
427 		results[0] = count;
428 	}
429 	igt_fork(child, 1) {
430 		unsigned long count = 0;
431 
432 		igt_until_timeout(timeout) {
433 			char buf[128];
434 
435 			switch (mode) {
436 			default:
437 				flip_nonblocking(display, flip_pipe, mode >= flip_test_atomic, &fb_info, NULL);
438 				break;
439 			case flip_test_atomic_transitions:
440 			case flip_test_atomic_transitions_varying_size:
441 				transition_nonblocking(display, flip_pipe, &fb_info, &argb_fb, count & 1);
442 				break;
443 			}
444 
445 			while (read(display->drm_fd, buf, sizeof(buf)) < 0 &&
446 			       (errno == EINTR || errno == EAGAIN))
447 				;
448 			count++;
449 		}
450 
451 		igt_debug("flip count=%lu\n", count);
452 		results[1] = count;
453 	}
454 	igt_waitchildren();
455 
456 	munmap(results, PAGE_SIZE);
457 
458 	igt_remove_fb(display->drm_fd, &fb_info);
459 	if (flip_pipe != cursor_pipe)
460 		igt_remove_fb(display->drm_fd, &fb_info2);
461 	igt_remove_fb(display->drm_fd, &cursor_fb);
462 	if (argb_fb.gem_handle)
463 		igt_remove_fb(display->drm_fd, &argb_fb);
464 	if (cursor_fb2.gem_handle)
465 		igt_remove_fb(display->drm_fd, &cursor_fb2);
466 }
467 
pipe_select(enum pipe pipe)468 static inline uint32_t pipe_select(enum pipe pipe)
469 {
470 	if (pipe > 1)
471 		return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
472 	else if (pipe > 0)
473 		return DRM_VBLANK_SECONDARY;
474 	else
475 		return 0;
476 }
477 
get_vblank(int fd,enum pipe pipe,unsigned flags)478 static unsigned get_vblank(int fd, enum pipe pipe, unsigned flags)
479 {
480 	union drm_wait_vblank vbl;
481 
482 	memset(&vbl, 0, sizeof(vbl));
483 	vbl.request.type = DRM_VBLANK_RELATIVE | pipe_select(pipe) | flags;
484 	if (drmIoctl(fd, DRM_IOCTL_WAIT_VBLANK, &vbl))
485 		return 0;
486 
487 	return vbl.reply.sequence;
488 }
489 
490 enum basic_flip_cursor {
491 	FLIP_BEFORE_CURSOR,
492 	FLIP_AFTER_CURSOR
493 };
494 
495 #define BASIC_BUSY 0x1
496 
basic_flip_cursor(igt_display_t * display,enum flip_test mode,enum basic_flip_cursor order,unsigned flags)497 static void basic_flip_cursor(igt_display_t *display,
498 			      enum flip_test mode,
499 			      enum basic_flip_cursor order,
500 			      unsigned flags)
501 {
502 	struct drm_mode_cursor arg[2];
503 	struct drm_event_vblank vbl;
504 	struct igt_fb fb_info, cursor_fb, cursor_fb2, argb_fb;
505 	unsigned vblank_start;
506 	enum pipe pipe = find_connected_pipe(display, false);
507 	igt_spin_t *spin;
508 	int i, miss1 = 0, miss2 = 0, delta;
509 
510 	if (mode >= flip_test_atomic)
511 		igt_require(display->is_atomic);
512 
513 	igt_require(set_fb_on_crtc(display, pipe, &fb_info));
514 
515 	igt_create_color_fb(display->drm_fd, 64, 64, DRM_FORMAT_ARGB8888, 0, 1., 1., 1., &cursor_fb);
516 	set_cursor_on_pipe(display, pipe, &cursor_fb);
517 	populate_cursor_args(display, pipe, arg, &cursor_fb);
518 
519 	prepare_flip_test(display, mode, pipe, pipe, arg, &fb_info, &argb_fb, &cursor_fb2);
520 
521 	igt_display_commit2(display, display->is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY);
522 
523 	/* Quick sanity check that we can update a cursor in a single vblank */
524 	vblank_start = get_vblank(display->drm_fd, pipe, DRM_VBLANK_NEXTONMISS);
525 	igt_assert_eq(get_vblank(display->drm_fd, pipe, 0), vblank_start);
526 	do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, &arg[0]);
527 	igt_assert_eq(get_vblank(display->drm_fd, pipe, 0), vblank_start);
528 
529 	for (i = 0; i < 25; i++) {
530 		bool miss;
531 
532 		/* Bind the cursor first to warm up */
533 		do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, &arg[0]);
534 
535 		spin = NULL;
536 		if (flags & BASIC_BUSY)
537 			spin = igt_spin_new(display->drm_fd,
538 					    .dependency = fb_info.gem_handle);
539 
540 		/* Start with a synchronous query to align with the vblank */
541 		vblank_start = get_vblank(display->drm_fd, pipe, DRM_VBLANK_NEXTONMISS);
542 
543 		switch (order) {
544 		case FLIP_BEFORE_CURSOR:
545 			switch (mode) {
546 			default:
547 				flip_nonblocking(display, pipe, mode >= flip_test_atomic, &fb_info, NULL);
548 				break;
549 			case flip_test_atomic_transitions:
550 			case flip_test_atomic_transitions_varying_size:
551 				transition_nonblocking(display, pipe, &fb_info, &argb_fb, 0);
552 				break;
553 			}
554 
555 			delta = get_vblank(display->drm_fd, pipe, 0) - vblank_start;
556 			miss = delta != 0;
557 
558 			do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, &arg[0]);
559 			break;
560 
561 		case FLIP_AFTER_CURSOR:
562 			do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, &arg[0]);
563 
564 			delta = get_vblank(display->drm_fd, pipe, 0) - vblank_start;
565 			miss = delta != 0;
566 
567 			switch (mode) {
568 			default:
569 				flip_nonblocking(display, pipe, mode >= flip_test_atomic, &fb_info, NULL);
570 				break;
571 			case flip_test_atomic_transitions:
572 			case flip_test_atomic_transitions_varying_size:
573 				transition_nonblocking(display, pipe, &fb_info, &argb_fb, 0);
574 				break;
575 			}
576 		}
577 
578 		delta = get_vblank(display->drm_fd, pipe, 0) - vblank_start;
579 
580 		if (spin) {
581 			struct pollfd pfd = { display->drm_fd, POLLIN };
582 			igt_assert(poll(&pfd, 1, 0) == 0);
583 			igt_spin_free(display->drm_fd, spin);
584 		}
585 
586 		if (miss)
587 			{ /* compare nothing, already failed */ }
588 		else if (!cursor_slowpath(mode))
589 			miss = delta != 0;
590 		else
591 			miss = delta != 0 && delta != 1;
592 
593 		miss1 += miss;
594 
595 		igt_set_timeout(1, "Stuck page flip");
596 		igt_ignore_warn(read(display->drm_fd, &vbl, sizeof(vbl)));
597 		igt_reset_timeout();
598 
599 		if (miss1)
600 			continue;
601 
602 		delta = get_vblank(display->drm_fd, pipe, 0) - vblank_start;
603 
604 		if (!mode_requires_extra_vblank(mode))
605 			miss2 += delta != 1;
606 		else
607 			miss2 += delta != 1 && delta != 2;
608 	}
609 
610 	igt_fail_on_f(miss1 > 2 || miss1 + miss2 > 5, "Failed to evade %i vblanks and missed %i page flips\n", miss1, miss2);
611 	if (miss1 || miss2)
612 		igt_info("Failed to evade %i vblanks and missed %i page flips\n", miss1, miss2);
613 
614 	igt_remove_fb(display->drm_fd, &fb_info);
615 	igt_remove_fb(display->drm_fd, &cursor_fb);
616 
617 	if (argb_fb.gem_handle)
618 		igt_remove_fb(display->drm_fd, &argb_fb);
619 	if (cursor_fb2.gem_handle)
620 		igt_remove_fb(display->drm_fd, &cursor_fb2);
621 }
622 
623 static int
get_cursor_updates_per_vblank(igt_display_t * display,enum pipe pipe,struct drm_mode_cursor * arg)624 get_cursor_updates_per_vblank(igt_display_t *display, enum pipe pipe,
625 			      struct drm_mode_cursor *arg)
626 {
627 	int target;
628 
629 	for (target = 65536; target; target /= 2) {
630 		unsigned vblank_start = get_vblank(display->drm_fd, pipe, DRM_VBLANK_NEXTONMISS);
631 
632 		igt_assert_eq(get_vblank(display->drm_fd, pipe, 0), vblank_start);
633 
634 		for (int n = 0; n < target; n++)
635 			do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, arg);
636 		if (get_vblank(display->drm_fd, pipe, 0) == vblank_start)
637 			break;
638 	}
639 
640 	/*
641 	  * Divide by 4, to handle variations in amount of vblanks
642 	  * caused by cpufreq throttling.
643 	  */
644 	target /= 4;
645 	igt_require(target > 1);
646 
647 	igt_info("Using a target of %d cursor updates per quarter-vblank\n", target);
648 
649 	return target;
650 }
651 
flip_vs_cursor(igt_display_t * display,enum flip_test mode,int nloops)652 static void flip_vs_cursor(igt_display_t *display, enum flip_test mode, int nloops)
653 {
654 	struct drm_mode_cursor arg[2];
655 	struct drm_event_vblank vbl;
656 	struct igt_fb fb_info, cursor_fb, cursor_fb2, argb_fb;
657 	unsigned vblank_start;
658 	int target, cpu;
659 	enum pipe pipe = find_connected_pipe(display, false);
660 	volatile unsigned long *shared;
661 	cpu_set_t mask, oldmask;
662 
663 	if (mode >= flip_test_atomic)
664 		igt_require(display->is_atomic);
665 
666 	igt_require(set_fb_on_crtc(display, pipe, &fb_info));
667 
668 	igt_create_color_fb(display->drm_fd, 64, 64, DRM_FORMAT_ARGB8888, 0, 1., 1., 1., &cursor_fb);
669 	set_cursor_on_pipe(display, pipe, &cursor_fb);
670 	populate_cursor_args(display, pipe, arg, &cursor_fb);
671 
672 	prepare_flip_test(display, mode, pipe, pipe, arg, &fb_info, &argb_fb, &cursor_fb2);
673 
674 	igt_display_commit2(display, display->is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY);
675 
676 	if (nloops)
677 		target = get_cursor_updates_per_vblank(display, pipe, &arg[0]);
678 	else
679 		target = 1;
680 
681 	vblank_start = get_vblank(display->drm_fd, pipe, DRM_VBLANK_NEXTONMISS);
682 	igt_assert_eq(get_vblank(display->drm_fd, pipe, 0), vblank_start);
683 	for (int n = 0; n < target; n++)
684 		do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, &arg[0]);
685 	igt_assert_eq(get_vblank(display->drm_fd, pipe, 0), vblank_start);
686 
687 	/*
688 	 * There are variations caused by using cpu frequency changing. To
689 	 * eliminate those we force this test to run on the same cpu as an
690 	 * idle thread that does a busy loop of sched_yield(); The effect is
691 	 * that we don't throttle the cpu to a lower frequency, and the
692 	 * variations caused by cpu speed changing are eliminated.
693 	 */
694 	if (target > 1) {
695 		shared = mmap(NULL, PAGE_SIZE, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
696 		igt_assert(shared != MAP_FAILED);
697 
698 		cpu = sched_getcpu();
699 		igt_assert(cpu >= 0);
700 
701 		CPU_ZERO(&mask);
702 		CPU_SET(cpu, &mask);
703 		sched_getaffinity(0, sizeof(oldmask), &oldmask);
704 		sched_setaffinity(0, sizeof(mask), &mask);
705 
706 		shared[0] = 0;
707 
708 		igt_fork(child, 1) {
709 			struct sched_param parm = { .sched_priority = 0 };
710 
711 			igt_assert(sched_setscheduler(0, SCHED_IDLE, &parm) == 0);
712 
713 			while (!shared[0])
714 				sched_yield();
715 		}
716 	}
717 
718 	do {
719 		/* Bind the cursor first to warm up */
720 		do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, &arg[nloops & 1]);
721 
722 		/* Start with a synchronous query to align with the vblank */
723 		vblank_start = get_vblank(display->drm_fd, pipe, DRM_VBLANK_NEXTONMISS);
724 		switch (mode) {
725 		default:
726 			flip_nonblocking(display, pipe, mode >= flip_test_atomic, &fb_info, NULL);
727 			break;
728 		case flip_test_atomic_transitions:
729 		case flip_test_atomic_transitions_varying_size:
730 			transition_nonblocking(display, pipe, &fb_info, &argb_fb, (nloops & 2) /2);
731 			break;
732 		}
733 
734 		/* The nonblocking flip should not have delayed us */
735 		igt_assert_eq(get_vblank(display->drm_fd, pipe, 0), vblank_start);
736 		for (int n = 0; n < target; n++)
737 			do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, &arg[nloops & 1]);
738 
739 		/* Nor should it have delayed the following cursor update */
740 		if (!cursor_slowpath(mode))
741 			igt_assert_eq(get_vblank(display->drm_fd, pipe, 0), vblank_start);
742 		else
743 			igt_assert_lte(get_vblank(display->drm_fd, pipe, 0), vblank_start + 1);
744 
745 		igt_set_timeout(1, "Stuck page flip");
746 		igt_ignore_warn(read(display->drm_fd, &vbl, sizeof(vbl)));
747 
748 		if (!mode_requires_extra_vblank(mode))
749 			igt_assert_eq(get_vblank(display->drm_fd, pipe, 0), vblank_start + 1);
750 		else
751 			igt_assert_lte(get_vblank(display->drm_fd, pipe, 0), vblank_start + 2);
752 
753 		igt_reset_timeout();
754 	} while (nloops--);
755 
756 	if (target > 1) {
757 		shared[0] = 1;
758 		igt_waitchildren();
759 		munmap((void *)shared, PAGE_SIZE);
760 		sched_setaffinity(0, sizeof(oldmask), &oldmask);
761 	}
762 
763 	igt_remove_fb(display->drm_fd, &fb_info);
764 	igt_remove_fb(display->drm_fd, &cursor_fb);
765 
766 	if (argb_fb.gem_handle)
767 		igt_remove_fb(display->drm_fd, &argb_fb);
768 	if (cursor_fb2.gem_handle)
769 		igt_remove_fb(display->drm_fd, &cursor_fb2);
770 }
771 
nonblocking_modeset_vs_cursor(igt_display_t * display,int loops)772 static void nonblocking_modeset_vs_cursor(igt_display_t *display, int loops)
773 {
774 	struct igt_fb fb_info, cursor_fb;
775 	igt_output_t *output;
776 	enum pipe pipe = find_connected_pipe(display, false);
777 	struct drm_mode_cursor arg[2];
778 	igt_plane_t *cursor = NULL, *plane;
779 
780 	igt_require(display->is_atomic);
781 	igt_require((output = set_fb_on_crtc(display, pipe, &fb_info)));
782 	igt_create_color_fb(display->drm_fd, 64, 64, DRM_FORMAT_ARGB8888, 0, 1., 1., 1., &cursor_fb);
783 	set_cursor_on_pipe(display, pipe, &cursor_fb);
784 	populate_cursor_args(display, pipe, arg, &cursor_fb);
785 	arg[0].flags |= DRM_MODE_CURSOR_BO;
786 
787 	for_each_plane_on_pipe(display, pipe, plane) {
788 		if (plane->type != DRM_PLANE_TYPE_CURSOR)
789 			continue;
790 
791 		cursor = plane;
792 		break;
793 	}
794 
795 	igt_skip_on(!cursor);
796 
797 	/*
798 	 * Start disabled. No way around it, since the first atomic
799 	 * commit may be unreliable with amount of events sent.
800 	 */
801 	igt_output_set_pipe(output, PIPE_NONE);
802 	igt_display_commit2(display, COMMIT_ATOMIC);
803 
804 	while (loops--) {
805 		unsigned flags;
806 		struct pollfd pfd = { display->drm_fd, POLLIN };
807 		struct drm_event_vblank vbl;
808 
809 		flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
810 		flags |= DRM_MODE_ATOMIC_NONBLOCK;
811 		flags |= DRM_MODE_PAGE_FLIP_EVENT;
812 
813 		/*
814 		 * Test that a cursor update after a nonblocking modeset
815 		 * works as intended. It should block until the modeset completes.
816 		 */
817 
818 		igt_output_set_pipe(output, pipe);
819 		igt_plane_set_fb(cursor, NULL);
820 		igt_display_commit_atomic(display, flags, NULL);
821 
822 		igt_assert_eq(0, poll(&pfd, 1, 0));
823 		igt_assert_eq(0, pfd.revents);
824 
825 		do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, &arg[0]);
826 
827 		igt_assert_eq(1, poll(&pfd, 1, 0));
828 		igt_assert_eq(POLLIN, pfd.revents);
829 
830 		igt_set_timeout(1, "Stuck page flip");
831 		igt_ignore_warn(read(display->drm_fd, &vbl, sizeof(vbl)));
832 		igt_reset_timeout();
833 
834 		igt_output_set_pipe(output, PIPE_NONE);
835 		igt_display_commit_atomic(display, flags, NULL);
836 
837 		igt_assert_eq(0, poll(&pfd, 1, 0));
838 		igt_assert_eq(0, pfd.revents);
839 
840 		/* Same for cursor on disabled crtc. */
841 		do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, &arg[0]);
842 
843 		igt_assert_eq(1, poll(&pfd, 1, 0));
844 		igt_assert_eq(POLLIN, pfd.revents);
845 
846 		igt_set_timeout(1, "Stuck page flip");
847 		igt_ignore_warn(read(display->drm_fd, &vbl, sizeof(vbl)));
848 		igt_reset_timeout();
849 	}
850 
851 	igt_remove_fb(display->drm_fd, &fb_info);
852 	igt_remove_fb(display->drm_fd, &cursor_fb);
853 }
854 
two_screens_flip_vs_cursor(igt_display_t * display,int nloops,bool modeset,bool atomic)855 static void two_screens_flip_vs_cursor(igt_display_t *display, int nloops, bool modeset, bool atomic)
856 {
857 	struct drm_mode_cursor arg1[2], arg2[2];
858 	struct igt_fb fb_info, fb2_info, cursor_fb;
859 	enum pipe pipe = find_connected_pipe(display, false);
860 	enum pipe pipe2 = find_connected_pipe(display, true);
861 	igt_output_t *output, *output2;
862 	bool enabled = false;
863 	volatile unsigned long *shared;
864 	unsigned flags = 0, vblank_start;
865 	struct drm_event_vblank vbl;
866 	int ret;
867 
868 	if (modeset) {
869 		uint64_t val;
870 
871 		igt_fail_on(!atomic);
872 		igt_require(drmGetCap(display->drm_fd, DRM_CAP_CRTC_IN_VBLANK_EVENT, &val) == 0);
873 	}
874 
875 	shared = mmap(NULL, PAGE_SIZE, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
876 	igt_assert(shared != MAP_FAILED);
877 
878 	igt_fail_on(modeset && !atomic);
879 
880 	if (atomic)
881 		igt_require(display->is_atomic);
882 
883 	igt_require((output = set_fb_on_crtc(display, pipe, &fb_info)));
884 	igt_require((output2 = set_fb_on_crtc(display, pipe2, &fb2_info)));
885 
886 	igt_create_color_fb(display->drm_fd, 64, 64, DRM_FORMAT_ARGB8888, 0, 1., 1., 1., &cursor_fb);
887 	set_cursor_on_pipe(display, pipe, &cursor_fb);
888 	populate_cursor_args(display, pipe, arg1, &cursor_fb);
889 
890 	arg1[1].x = arg1[1].y = 192;
891 
892 	set_cursor_on_pipe(display, pipe2, &cursor_fb);
893 	populate_cursor_args(display, pipe2, arg2, &cursor_fb);
894 
895 	arg2[1].x = arg2[1].y = 192;
896 
897 
898 	igt_display_commit2(display, display->is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY);
899 
900 	igt_fork(child, 2) {
901 		struct drm_mode_cursor *arg = child ? arg2 : arg1;
902 
903 		while (!shared[0])
904 			do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR,
905 				 &arg[!shared[1]]);
906 	}
907 
908 	if (modeset) {
909 		igt_plane_t *plane = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
910 
911 		flags = DRM_MODE_ATOMIC_ALLOW_MODESET |
912 			DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_PAGE_FLIP_EVENT;
913 
914 		/* Disable pipe2 */
915 		igt_output_set_pipe(output2, PIPE_NONE);
916 		igt_display_commit_atomic(display, flags, NULL);
917 		enabled = false;
918 
919 		/*
920 		 * Try a page flip on crtc 1, if we succeed pump page flips and
921 		 * modesets interleaved, else do a single atomic commit with both.
922 		 */
923 		vblank_start = get_vblank(display->drm_fd, pipe, DRM_VBLANK_NEXTONMISS);
924 		igt_plane_set_fb(plane, &fb_info);
925 		ret = igt_display_try_commit_atomic(display, flags, (void*)(ptrdiff_t)vblank_start);
926 		igt_assert(!ret || ret == -EBUSY);
927 
928 		if (ret == -EBUSY) {
929 			/* Force completion on both pipes, and generate event. */
930 			igt_display_commit_atomic(display, flags, NULL);
931 
932 			while (nloops--) {
933 				shared[1] = nloops & 1;
934 
935 				igt_set_timeout(35, "Stuck modeset");
936 				igt_assert_eq(read(display->drm_fd, &vbl, sizeof(vbl)), sizeof(vbl));
937 				igt_assert_eq(read(display->drm_fd, &vbl, sizeof(vbl)), sizeof(vbl));
938 				igt_reset_timeout();
939 
940 				if (!nloops)
941 					break;
942 
943 				/* Commit page flip and modeset simultaneously. */
944 				igt_plane_set_fb(plane, &fb_info);
945 				igt_output_set_pipe(output2, enabled ? PIPE_NONE : pipe2);
946 				enabled = !enabled;
947 
948 				igt_set_timeout(5, "Scheduling modeset\n");
949 				do {
950 					ret = igt_display_try_commit_atomic(display, flags, NULL);
951 				} while (ret == -EBUSY);
952 				igt_assert(!ret);
953 				igt_reset_timeout();
954 			}
955 
956 			goto done;
957 		}
958 	} else {
959 		vblank_start = get_vblank(display->drm_fd, pipe, DRM_VBLANK_NEXTONMISS);
960 		flip_nonblocking(display, pipe, atomic, &fb_info, (void*)(ptrdiff_t)vblank_start);
961 
962 		vblank_start = get_vblank(display->drm_fd, pipe2, DRM_VBLANK_NEXTONMISS);
963 		flip_nonblocking(display, pipe2, atomic, &fb2_info, (void*)(ptrdiff_t)vblank_start);
964 	}
965 
966 	while (nloops) {
967 		shared[1] = nloops & 1;
968 
969 		if (!modeset || nloops > 1)
970 			igt_set_timeout(1, "Stuck page flip");
971 		else
972 			igt_set_timeout(35, "Stuck modeset");
973 		igt_assert_eq(read(display->drm_fd, &vbl, sizeof(vbl)), sizeof(vbl));
974 		igt_reset_timeout();
975 
976 		vblank_start = vbl.user_data;
977 		if (!modeset)
978 			igt_assert_eq(vbl.sequence, vblank_start + 1);
979 
980 		/* Do not requeue on the last 2 events. */
981 		if (nloops <= 2) {
982 			nloops--;
983 			continue;
984 		}
985 
986 		if (vbl.crtc_id == display->pipes[pipe].crtc_id) {
987 			vblank_start = get_vblank(display->drm_fd, pipe, DRM_VBLANK_NEXTONMISS);
988 			flip_nonblocking(display, pipe, atomic, &fb_info, (void*)(ptrdiff_t)vblank_start);
989 		} else {
990 			igt_assert(vbl.crtc_id == display->pipes[pipe2].crtc_id);
991 
992 			nloops--;
993 
994 			if (!modeset) {
995 				vblank_start = get_vblank(display->drm_fd, pipe2, DRM_VBLANK_NEXTONMISS);
996 				flip_nonblocking(display, pipe2, atomic, &fb2_info, (void*)(ptrdiff_t)vblank_start);
997 			} else {
998 				igt_output_set_pipe(output2, enabled ? PIPE_NONE : pipe2);
999 
1000 				igt_set_timeout(1, "Scheduling modeset\n");
1001 				do {
1002 					ret = igt_display_try_commit_atomic(display, flags, NULL);
1003 				} while (ret == -EBUSY);
1004 				igt_assert(!ret);
1005 				igt_reset_timeout();
1006 
1007 				enabled = !enabled;
1008 			}
1009 		}
1010 	}
1011 
1012 done:
1013 	shared[0] = 1;
1014 	igt_waitchildren();
1015 
1016 	igt_remove_fb(display->drm_fd, &fb_info);
1017 	igt_remove_fb(display->drm_fd, &fb2_info);
1018 	igt_remove_fb(display->drm_fd, &cursor_fb);
1019 	munmap((void *)shared, PAGE_SIZE);
1020 }
1021 
cursor_vs_flip(igt_display_t * display,enum flip_test mode,int nloops)1022 static void cursor_vs_flip(igt_display_t *display, enum flip_test mode, int nloops)
1023 {
1024 	struct drm_mode_cursor arg[2];
1025 	struct drm_event_vblank vbl;
1026 	struct igt_fb fb_info, cursor_fb, cursor_fb2, argb_fb;
1027 	unsigned vblank_start, vblank_last;
1028 	volatile unsigned long *shared;
1029 	long target;
1030 	enum pipe pipe = find_connected_pipe(display, false);
1031 	igt_output_t *output;
1032 	uint32_t vrefresh;
1033 	int fail_count;
1034 
1035 	if (mode >= flip_test_atomic)
1036 		igt_require(display->is_atomic);
1037 
1038 	shared = mmap(NULL, PAGE_SIZE, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
1039 	igt_assert(shared != MAP_FAILED);
1040 
1041 	igt_require((output = set_fb_on_crtc(display, pipe, &fb_info)));
1042 	vrefresh = igt_output_get_mode(output)->vrefresh;
1043 
1044 	igt_create_color_fb(display->drm_fd, 64, 64, DRM_FORMAT_ARGB8888, 0, 1., 1., 1., &cursor_fb);
1045 	set_cursor_on_pipe(display, pipe, &cursor_fb);
1046 	populate_cursor_args(display, pipe, arg, &cursor_fb);
1047 
1048 	prepare_flip_test(display, mode, pipe, pipe, arg, &fb_info, &argb_fb, &cursor_fb2);
1049 
1050 	igt_display_commit2(display, display->is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY);
1051 
1052 	target = get_cursor_updates_per_vblank(display, pipe, &arg[0]);
1053 
1054 	fail_count = 0;
1055 
1056 	for (int i = 0; i < nloops; i++) {
1057 		shared[0] = 0;
1058 		igt_fork(child, 1) {
1059 			unsigned long count = 0;
1060 			while (!shared[0]) {
1061 				do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, &arg[i & 1]);
1062 				count++;
1063 			}
1064 			igt_debug("child: %lu cursor updates\n", count);
1065 			shared[0] = count;
1066 		}
1067 
1068 		switch (mode) {
1069 		default:
1070 			flip_nonblocking(display, pipe, mode >= flip_test_atomic, &fb_info, NULL);
1071 			break;
1072 		case flip_test_atomic_transitions:
1073 		case flip_test_atomic_transitions_varying_size:
1074 			transition_nonblocking(display, pipe, &fb_info, &argb_fb, (i & 2) >> 1);
1075 			break;
1076 		}
1077 
1078 		igt_assert_eq(read(display->drm_fd, &vbl, sizeof(vbl)), sizeof(vbl));
1079 		vblank_start = vblank_last = vbl.sequence;
1080 		for (int n = 0; n < vrefresh / 2; n++) {
1081 			flip_nonblocking(display, pipe, mode >= flip_test_atomic, &fb_info, NULL);
1082 
1083 			igt_assert_eq(read(display->drm_fd, &vbl, sizeof(vbl)), sizeof(vbl));
1084 			if (vbl.sequence != vblank_last + 1) {
1085 				igt_info("page flip %d was delayed, missed %d frames\n",
1086 					 n, vbl.sequence - vblank_last - 1);
1087 			}
1088 			vblank_last = vbl.sequence;
1089 		}
1090 
1091 		if (!cursor_slowpath(mode))
1092 			igt_assert_lte(vbl.sequence, vblank_start + 5 * vrefresh / 8);
1093 
1094 		shared[0] = 1;
1095 		igt_waitchildren();
1096 		if (shared[0] <= vrefresh*target / 2) {
1097 			fail_count++;
1098 			igt_critical("completed %lu cursor updated in a period of %u flips, "
1099 				     "we expect to complete approximately %lu updates, "
1100 				     "with the threshold set at %lu\n",
1101 				     shared[0], vrefresh / 2,
1102 				     vrefresh*target, vrefresh*target / 2);
1103 		}
1104 	}
1105 
1106 	igt_assert_f(fail_count == 0,
1107 		     "Failed to meet cursor update expectations in %d out of %d iterations\n",
1108 		     fail_count, nloops);
1109 
1110 	igt_remove_fb(display->drm_fd, &fb_info);
1111 	igt_remove_fb(display->drm_fd, &cursor_fb);
1112 	munmap((void *)shared, PAGE_SIZE);
1113 	if (argb_fb.gem_handle)
1114 		igt_remove_fb(display->drm_fd, &argb_fb);
1115 	if (cursor_fb2.gem_handle)
1116 		igt_remove_fb(display->drm_fd, &cursor_fb2);
1117 }
1118 
two_screens_cursor_vs_flip(igt_display_t * display,int nloops,bool atomic)1119 static void two_screens_cursor_vs_flip(igt_display_t *display, int nloops, bool atomic)
1120 {
1121 	struct drm_mode_cursor arg[2][2];
1122 	struct drm_event_vblank vbl;
1123 	struct igt_fb fb_info[2], cursor_fb;
1124 	volatile unsigned long *shared;
1125 	int target[2];
1126 	enum pipe pipe[2] = {
1127 		find_connected_pipe(display, false),
1128 		find_connected_pipe(display, true)
1129 	};
1130 	igt_output_t *outputs[2];
1131 
1132 	shared = mmap(NULL, PAGE_SIZE, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
1133 	igt_assert(shared != MAP_FAILED);
1134 
1135 	if (atomic)
1136 		igt_require(display->is_atomic);
1137 
1138 	igt_require((outputs[0] = set_fb_on_crtc(display, pipe[0], &fb_info[0])));
1139 	igt_require((outputs[1] = set_fb_on_crtc(display, pipe[1], &fb_info[1])));
1140 
1141 	igt_create_color_fb(display->drm_fd, 64, 64, DRM_FORMAT_ARGB8888, 0, 1., 1., 1., &cursor_fb);
1142 
1143 	set_cursor_on_pipe(display, pipe[0], &cursor_fb);
1144 	populate_cursor_args(display, pipe[0], arg[0], &cursor_fb);
1145 	arg[0][1].x = arg[0][1].y = 192;
1146 
1147 	set_cursor_on_pipe(display, pipe[1], &cursor_fb);
1148 	populate_cursor_args(display, pipe[1], arg[1], &cursor_fb);
1149 	arg[1][1].x =  arg[1][1].y = 192;
1150 
1151 	igt_display_commit2(display, display->is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY);
1152 
1153 	target[0] = get_cursor_updates_per_vblank(display, pipe[0], &arg[0][0]);
1154 	target[1] = get_cursor_updates_per_vblank(display, pipe[1], &arg[1][0]);
1155 
1156 	for (int i = 0; i < nloops; i++) {
1157 		unsigned long vrefresh[2];
1158 		unsigned vblank_start[2], vblank_last[2];
1159 		int done[2] = {};
1160 
1161 		vrefresh[0] = igt_output_get_mode(outputs[0])->vrefresh;
1162 		vrefresh[1] = igt_output_get_mode(outputs[1])->vrefresh;
1163 
1164 		shared[0] = 0;
1165 		shared[1] = 0;
1166 		igt_fork(child, 2) {
1167 			unsigned long count = 0;
1168 
1169 			while (!shared[child]) {
1170 				do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, &arg[child][(i >> child) & 1]);
1171 				count++;
1172 			}
1173 			igt_debug("child %i: %lu cursor updates\n", child, count);
1174 			shared[child] = count;
1175 		}
1176 
1177 		flip_nonblocking(display, pipe[0], atomic, &fb_info[0], (void *)0UL);
1178 		flip_nonblocking(display, pipe[1], atomic, &fb_info[1], (void *)1UL);
1179 
1180 		for (int n = 0; n < vrefresh[0] / 2 + vrefresh[1] / 2; n++) {
1181 			unsigned long child;
1182 
1183 			igt_assert_eq(read(display->drm_fd, &vbl, sizeof(vbl)), sizeof(vbl));
1184 			child = vbl.user_data;
1185 
1186 			if (!done[child]++)
1187 				vblank_start[child] = vbl.sequence;
1188 			else if (vbl.sequence != vblank_last[child] + 1)
1189 				igt_info("page flip %d was delayed, missed %d frames\n",
1190 					 done[child], vbl.sequence - vblank_last[child] - 1);
1191 
1192 			vblank_last[child] = vbl.sequence;
1193 
1194 			if (done[child] < vrefresh[child] / 2) {
1195 				flip_nonblocking(display, pipe[child], atomic, &fb_info[child], (void *)child);
1196 			} else {
1197 				igt_assert_lte(vbl.sequence, vblank_start[child] + 5 * vrefresh[child] / 8);
1198 
1199 				shared[child] = 1;
1200 			}
1201 		}
1202 
1203 		igt_assert_eq(done[0], vrefresh[0] / 2);
1204 		igt_assert_eq(done[1], vrefresh[1] / 2);
1205 
1206 		igt_waitchildren();
1207 		for (int child = 0; child < 2; child++)
1208 			igt_assert_f(shared[child] > vrefresh[child]*target[child] / 2,
1209 				    "completed %lu cursor updated in a period of %lu flips, "
1210 				    "we expect to complete approximately %lu updates, "
1211 				    "with the threshold set at %lu\n",
1212 				    shared[child], vrefresh[child] / 2,
1213 				    vrefresh[child]*target[child], vrefresh[child]*target[child] / 2);
1214 	}
1215 
1216 	igt_remove_fb(display->drm_fd, &fb_info[0]);
1217 	igt_remove_fb(display->drm_fd, &fb_info[1]);
1218 	igt_remove_fb(display->drm_fd, &cursor_fb);
1219 	munmap((void *)shared, PAGE_SIZE);
1220 }
1221 
flip_vs_cursor_crc(igt_display_t * display,bool atomic)1222 static void flip_vs_cursor_crc(igt_display_t *display, bool atomic)
1223 {
1224 	struct drm_mode_cursor arg[2];
1225 	struct drm_event_vblank vbl;
1226 	struct igt_fb fb_info, cursor_fb;
1227 	unsigned vblank_start;
1228 	enum pipe pipe = find_connected_pipe(display, false);
1229 	igt_crc_t crcs[3];
1230 
1231 	if (atomic)
1232 		igt_require(display->is_atomic);
1233 
1234 	igt_require(set_fb_on_crtc(display, pipe, &fb_info));
1235 
1236 	igt_create_color_fb(display->drm_fd, 64, 64, DRM_FORMAT_ARGB8888, 0, 1., 1., 1., &cursor_fb);
1237 	populate_cursor_args(display, pipe, arg, &cursor_fb);
1238 
1239 	igt_display_commit2(display, display->is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY);
1240 
1241 	pipe_crc = igt_pipe_crc_new(display->drm_fd, pipe, INTEL_PIPE_CRC_SOURCE_AUTO);
1242 
1243 	set_cursor_on_pipe(display, pipe, &cursor_fb);
1244 	igt_display_commit2(display, COMMIT_UNIVERSAL);
1245 
1246 	/* Collect reference crcs, crcs[0] last. */
1247 	do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, &arg[1]);
1248 	igt_pipe_crc_collect_crc(pipe_crc, &crcs[1]);
1249 
1250 	do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, &arg[0]);
1251 	igt_pipe_crc_collect_crc(pipe_crc, &crcs[0]);
1252 
1253 	/* Disable cursor, and immediately queue a flip. Check if resulting crc is correct. */
1254 	for (int i = 1; i >= 0; i--) {
1255 		vblank_start = get_vblank(display->drm_fd, pipe, DRM_VBLANK_NEXTONMISS);
1256 
1257 		flip_nonblocking(display, pipe, atomic, &fb_info, NULL);
1258 		do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, &arg[i]);
1259 
1260 		igt_assert_eq(get_vblank(display->drm_fd, pipe, 0), vblank_start);
1261 
1262 		igt_set_timeout(1, "Stuck page flip");
1263 		igt_ignore_warn(read(display->drm_fd, &vbl, sizeof(vbl)));
1264 		igt_reset_timeout();
1265 
1266 		igt_assert_eq(get_vblank(display->drm_fd, pipe, 0), vblank_start + 1);
1267 
1268 		igt_pipe_crc_collect_crc(pipe_crc, &crcs[2]);
1269 
1270 		igt_assert_crc_equal(&crcs[i], &crcs[2]);
1271 	}
1272 
1273 	igt_remove_fb(display->drm_fd, &fb_info);
1274 	igt_remove_fb(display->drm_fd, &cursor_fb);
1275 }
1276 
flip_vs_cursor_busy_crc(igt_display_t * display,bool atomic)1277 static void flip_vs_cursor_busy_crc(igt_display_t *display, bool atomic)
1278 {
1279 	struct drm_mode_cursor arg[2];
1280 	struct drm_event_vblank vbl;
1281 	struct igt_fb fb_info[2], cursor_fb;
1282 	unsigned vblank_start;
1283 	enum pipe pipe = find_connected_pipe(display, false);
1284 	igt_pipe_t *pipe_connected = &display->pipes[pipe];
1285 	igt_plane_t *plane_primary = igt_pipe_get_plane_type(pipe_connected, DRM_PLANE_TYPE_PRIMARY);
1286 	igt_crc_t crcs[2], test_crc;
1287 
1288 	if (atomic)
1289 		igt_require(display->is_atomic);
1290 
1291 	igt_require(set_fb_on_crtc(display, pipe, &fb_info[0]));
1292 	igt_create_color_pattern_fb(display->drm_fd, fb_info[0].width, fb_info[0].height,
1293 				    DRM_FORMAT_XRGB8888, LOCAL_I915_FORMAT_MOD_X_TILED, .1, .1, .1, &fb_info[1]);
1294 
1295 	igt_create_color_fb(display->drm_fd, 64, 64, DRM_FORMAT_ARGB8888, 0, 1., 1., 1., &cursor_fb);
1296 	populate_cursor_args(display, pipe, arg, &cursor_fb);
1297 
1298 	igt_display_commit2(display, display->is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY);
1299 
1300 	pipe_crc = igt_pipe_crc_new(display->drm_fd, pipe, INTEL_PIPE_CRC_SOURCE_AUTO);
1301 
1302 	set_cursor_on_pipe(display, pipe, &cursor_fb);
1303 	igt_display_commit2(display, COMMIT_UNIVERSAL);
1304 
1305 	/* Collect reference crcs, crc[0] last for the loop. */
1306 	do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, &arg[1]);
1307 	igt_pipe_crc_collect_crc(pipe_crc, &crcs[1]);
1308 
1309 	do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, &arg[0]);
1310 	igt_pipe_crc_collect_crc(pipe_crc, &crcs[0]);
1311 
1312 	/*
1313 	  * Set fb 1 on primary at least once before flipping to force
1314 	  * setting the correct cache level, else we get a stall in the
1315 	  * page flip handler.
1316 	  */
1317 	igt_plane_set_fb(plane_primary, &fb_info[1]);
1318 	igt_display_commit2(display, COMMIT_UNIVERSAL);
1319 
1320 	igt_plane_set_fb(plane_primary, &fb_info[0]);
1321 	igt_display_commit2(display, COMMIT_UNIVERSAL);
1322 
1323 	/*
1324 	 * We must enable CRC collecting here since this may force
1325 	 * a modeset, and this loop is timing sensitive.
1326 	 */
1327 	igt_pipe_crc_start(pipe_crc);
1328 
1329 	/* Disable cursor, and immediately queue a flip. Check if resulting crc is correct. */
1330 	for (int i = 1; i >= 0; i--) {
1331 		igt_spin_t *spin;
1332 
1333 		spin = igt_spin_new(display->drm_fd,
1334 				    .dependency = fb_info[1].gem_handle);
1335 
1336 		vblank_start = get_vblank(display->drm_fd, pipe, DRM_VBLANK_NEXTONMISS);
1337 
1338 		flip_nonblocking(display, pipe, atomic, &fb_info[1], NULL);
1339 		do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, &arg[i]);
1340 
1341 		igt_assert_eq(get_vblank(display->drm_fd, pipe, 0), vblank_start);
1342 
1343 		igt_pipe_crc_get_current(display->drm_fd, pipe_crc, &test_crc);
1344 
1345 		igt_spin_free(display->drm_fd, spin);
1346 
1347 		igt_set_timeout(1, "Stuck page flip");
1348 		igt_ignore_warn(read(display->drm_fd, &vbl, sizeof(vbl)));
1349 		igt_reset_timeout();
1350 
1351 		igt_assert_lte(vblank_start + 1, get_vblank(display->drm_fd, pipe, 0));
1352 
1353 		igt_plane_set_fb(plane_primary, &fb_info[0]);
1354 		igt_display_commit2(display, COMMIT_UNIVERSAL);
1355 
1356 		igt_assert_crc_equal(&crcs[i], &test_crc);
1357 	}
1358 
1359 	igt_remove_fb(display->drm_fd, &fb_info[1]);
1360 	igt_remove_fb(display->drm_fd, &fb_info[0]);
1361 	igt_remove_fb(display->drm_fd, &cursor_fb);
1362 }
1363 
1364 igt_main
1365 {
1366 	const int ncpus = sysconf(_SC_NPROCESSORS_ONLN);
1367 	igt_display_t display = { .drm_fd = -1 };
1368 	int i;
1369 
1370 	igt_fixture {
1371 		display.drm_fd = drm_open_driver_master(DRIVER_ANY);
1372 		kmstest_set_vt_graphics_mode();
1373 
1374 		igt_display_require(&display, display.drm_fd);
1375 	}
1376 
1377 	igt_subtest_group {
1378 		enum pipe n;
for_each_pipe_static(n)1379 		for_each_pipe_static(n) {
1380 			errno = 0;
1381 
1382 			igt_fixture {
1383 				igt_skip_on(n >= display.n_pipes);
1384 			}
1385 
1386 			igt_subtest_f("pipe-%s-single-bo", kmstest_pipe_name(n))
1387 				stress(&display, n, 1, DRM_MODE_CURSOR_BO, 20);
1388 			igt_subtest_f("pipe-%s-single-move", kmstest_pipe_name(n))
1389 				stress(&display, n, 1, DRM_MODE_CURSOR_MOVE, 20);
1390 
1391 			igt_subtest_f("pipe-%s-forked-bo", kmstest_pipe_name(n))
1392 				stress(&display, n, ncpus, DRM_MODE_CURSOR_BO, 20);
1393 			igt_subtest_f("pipe-%s-forked-move", kmstest_pipe_name(n))
1394 				stress(&display, n, ncpus, DRM_MODE_CURSOR_MOVE, 20);
1395 
1396 			igt_subtest_f("pipe-%s-torture-bo", kmstest_pipe_name(n))
1397 				stress(&display, n, -ncpus, DRM_MODE_CURSOR_BO, 20);
1398 			igt_subtest_f("pipe-%s-torture-move", kmstest_pipe_name(n))
1399 				stress(&display, n, -ncpus, DRM_MODE_CURSOR_MOVE, 20);
1400 		}
1401 	}
1402 
1403 	igt_subtest("all-pipes-single-bo")
1404 		stress(&display, -1, 1, DRM_MODE_CURSOR_BO, 20);
1405 	igt_subtest("all-pipes-single-move")
1406 		stress(&display, -1, 1, DRM_MODE_CURSOR_MOVE, 20);
1407 
1408 	igt_subtest("all-pipes-forked-bo")
1409 		stress(&display, -1, ncpus, DRM_MODE_CURSOR_BO, 20);
1410 	igt_subtest("all-pipes-forked-move")
1411 		stress(&display, -1, ncpus, DRM_MODE_CURSOR_MOVE, 20);
1412 
1413 	igt_subtest("all-pipes-torture-bo")
1414 		stress(&display, -1, -ncpus, DRM_MODE_CURSOR_BO, 20);
1415 	igt_subtest("all-pipes-torture-move")
1416 		stress(&display, -1, -ncpus, DRM_MODE_CURSOR_MOVE, 20);
1417 
1418 	igt_subtest("nonblocking-modeset-vs-cursor-atomic")
1419 		nonblocking_modeset_vs_cursor(&display, 1);
1420 
1421 	igt_subtest("long-nonblocking-modeset-vs-cursor-atomic")
1422 		nonblocking_modeset_vs_cursor(&display, 16);
1423 
1424 	igt_subtest("2x-flip-vs-cursor-legacy")
1425 		two_screens_flip_vs_cursor(&display, 8, false, false);
1426 
1427 	igt_subtest("2x-flip-vs-cursor-atomic")
1428 		two_screens_flip_vs_cursor(&display, 8, false, true);
1429 
1430 	igt_subtest("2x-cursor-vs-flip-legacy")
1431 		two_screens_cursor_vs_flip(&display, 8, false);
1432 
1433 	igt_subtest("2x-long-flip-vs-cursor-legacy")
1434 		two_screens_flip_vs_cursor(&display, 150, false, false);
1435 
1436 	igt_subtest("2x-long-flip-vs-cursor-atomic")
1437 		two_screens_flip_vs_cursor(&display, 150, false, true);
1438 
1439 	igt_subtest("2x-long-cursor-vs-flip-legacy")
1440 		two_screens_cursor_vs_flip(&display, 50, false);
1441 
1442 	igt_subtest("2x-nonblocking-modeset-vs-cursor-atomic")
1443 		two_screens_flip_vs_cursor(&display, 4, true, true);
1444 
1445 	igt_subtest("2x-cursor-vs-flip-atomic")
1446 		two_screens_cursor_vs_flip(&display, 8, true);
1447 
1448 	igt_subtest("2x-long-nonblocking-modeset-vs-cursor-atomic")
1449 		two_screens_flip_vs_cursor(&display, 15, true, true);
1450 
1451 	igt_subtest("2x-long-cursor-vs-flip-atomic")
1452 		two_screens_cursor_vs_flip(&display, 50, true);
1453 
1454 	igt_subtest("flip-vs-cursor-crc-legacy")
1455 		flip_vs_cursor_crc(&display, false);
1456 
1457 	igt_subtest("flip-vs-cursor-crc-atomic")
1458 		flip_vs_cursor_crc(&display, true);
1459 
1460 	igt_subtest("flip-vs-cursor-busy-crc-legacy")
1461 		flip_vs_cursor_busy_crc(&display, false);
1462 
1463 	igt_subtest("flip-vs-cursor-busy-crc-atomic")
1464 		flip_vs_cursor_busy_crc(&display, true);
1465 
1466 	for (i = 0; i <= flip_test_last; i++) {
1467 		const char *modes[flip_test_last+1] = {
1468 			"legacy",
1469 			"varying-size",
1470 			"toggle",
1471 			"atomic",
1472 			"atomic-transitions",
1473 			"atomic-transitions-varying-size"
1474 		};
1475 		const char *prefix = "short-";
1476 
1477 		switch (i) {
1478 		case flip_test_legacy:
1479 		case flip_test_varying_size:
1480 		case flip_test_atomic:
1481 			prefix = "basic-";
1482 			break;
1483 		default: break;
1484 		}
1485 
1486 		igt_subtest_f("%sflip-before-cursor-%s", prefix, modes[i])
1487 			basic_flip_cursor(&display, i, FLIP_BEFORE_CURSOR, 0);
1488 
1489 		if (!cursor_slowpath(i)) {
1490 			igt_subtest_f("%sbusy-flip-before-cursor-%s", prefix, modes[i]) {
1491 				igt_require_gem(display.drm_fd);
1492 				basic_flip_cursor(&display, i, FLIP_BEFORE_CURSOR,
1493 						  BASIC_BUSY);
1494 			}
1495 		}
1496 
1497 		igt_subtest_f("%sflip-after-cursor-%s", prefix, modes[i])
1498 			basic_flip_cursor(&display, i, FLIP_AFTER_CURSOR, 0);
1499 
1500 		igt_subtest_f("flip-vs-cursor-%s", modes[i])
1501 			flip_vs_cursor(&display, i, 150);
1502 		igt_subtest_f("cursor-vs-flip-%s", modes[i])
1503 			cursor_vs_flip(&display, i, 50);
1504 
1505 		igt_subtest_f("cursorA-vs-flipA-%s", modes[i])
1506 			flip(&display, 0, 0, 10, i);
1507 
1508 		igt_subtest_f("cursorA-vs-flipB-%s", modes[i])
1509 			flip(&display, 0, 1, 10, i);
1510 
1511 		igt_subtest_f("cursorB-vs-flipA-%s", modes[i])
1512 			flip(&display, 1, 0, 10, i);
1513 
1514 		igt_subtest_f("cursorB-vs-flipB-%s", modes[i])
1515 			flip(&display, 1, 1, 10, i);
1516 	}
1517 
1518 	igt_fixture {
1519 		igt_display_fini(&display);
1520 	}
1521 }
1522