2 * Copyright © 2014 Intel Corporation
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:
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
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
31 #include "igt_debugfs.h"
33 #include "intel_chipset.h"
34 #include "ioctl_wrappers.h"
38 igt_display_t display;
39 igt_pipe_crc_t *pipe_crc;
40 drm_intel_bufmgr *bufmgr;
41 drm_intel_bo *busy_bo;
46 static void exec_nop(data_t *data, uint32_t handle, unsigned int ring)
48 struct intel_batchbuffer *batch;
51 batch = intel_batchbuffer_alloc(data->bufmgr, data->devid);
54 bo = gem_handle_to_libdrm_bo(data->bufmgr, data->drm_fd, "", handle);
57 /* add relocs to make sure the kernel will think we write to dst */
59 OUT_BATCH(MI_BATCH_BUFFER_END);
61 OUT_RELOC(bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
65 intel_batchbuffer_flush_on_ring(batch, ring);
66 intel_batchbuffer_free(batch);
68 drm_intel_bo_unreference(bo);
71 static void exec_blt(data_t *data)
73 struct intel_batchbuffer *batch;
76 batch = intel_batchbuffer_alloc(data->bufmgr, data->devid);
80 h = data->busy_bo->size / (8192 * 4);
83 for (i = 0; i < 40; i++) {
84 BLIT_COPY_BATCH_START(data->devid, 0);
85 OUT_BATCH((3 << 24) | /* 32 bits */
86 (0xcc << 16) | /* copy ROP */
88 OUT_BATCH(0 << 16 | 0);
89 OUT_BATCH(h << 16 | w);
90 OUT_RELOC(data->busy_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
91 BLIT_RELOC_UDW(data->devid);
92 OUT_BATCH(0 << 16 | 0);
94 OUT_RELOC(data->busy_bo, I915_GEM_DOMAIN_RENDER, 0, 0);
95 BLIT_RELOC_UDW(data->devid);
99 intel_batchbuffer_flush(batch);
100 intel_batchbuffer_free(batch);
103 static void page_flip_handler(int fd, unsigned int frame, unsigned int sec,
104 unsigned int usec, void *_data)
106 data_t *data = _data;
108 data->flip_done = true;
111 static void wait_for_flip(data_t *data, uint32_t flip_handle)
113 struct timeval timeout = {
117 drmEventContext evctx = {
118 .version = DRM_EVENT_CONTEXT_VERSION,
119 .page_flip_handler = page_flip_handler,
124 FD_SET(data->drm_fd, &fds);
126 while (!data->flip_done) {
127 int ret = select(data->drm_fd + 1, &fds, NULL, NULL, &timeout);
129 if (ret < 0 && errno == EINTR)
132 igt_assert(ret >= 0);
134 do_or_die(drmHandleEvent(data->drm_fd, &evctx));
138 * The flip completion may have been signalled prematurely, so
139 * also submit another nop batch and wait for it to make sure
140 * the ring has really been drained.
142 if (IS_GEN7(data->devid) || IS_GEN8(data->devid))
143 exec_nop(data, flip_handle, I915_EXEC_BLT);
145 exec_nop(data, flip_handle, I915_EXEC_RENDER);
146 gem_sync(data->drm_fd, flip_handle);
149 static void make_gpu_busy(data_t *data, uint32_t flip_handle)
152 * Make sure flip_handle has been used on the blt ring.
153 * This should make the flip use the same ring on gen7+.
155 if (IS_GEN7(data->devid) || IS_GEN8(data->devid))
156 exec_nop(data, flip_handle, I915_EXEC_BLT);
159 * Add a pile commands to the ring. The flip will be
160 * stuck behing these commands and hence gets delayed
166 * Make sure the render ring will block until the blt ring is clear.
167 * This is in case the flip will execute on the render ring and the
168 * blits were on the blt ring (this will be the case on gen6 at least).
170 * We can't add an explicit dependency between flip_handle and the
171 * blits since that would cause the driver to block until the blits
172 * have completed before it will perform a subsequent mmio flip,
173 * and so the test would fail to exercise the mmio vs. CS flip race.
175 if (HAS_BLT_RING(data->devid))
176 exec_nop(data, data->busy_bo->handle, I915_EXEC_RENDER);
180 * 1. set primary plane to full red
181 * 2. grab a reference crc
182 * 3. set primary plane to full blue
183 * 4. queue lots of GPU activity to delay the subsequent page flip
184 * 5. queue a page flip to the same blue fb
185 * 6. toggle a fullscreen sprite (green) on and back off again
186 * 7. set primary plane to red fb
187 * 8. wait for GPU to finish
188 * 9. compare current crc with reference crc
190 * We expect the primary plane to display full red at the end.
191 * If the sprite operations have interfered with the page flip,
192 * the driver may have mistakenly completed the flip before
193 * it was executed by the CS, and hence the subsequent mmio
194 * flips may have overtaken it. So once we've finished everything
195 * the CS flip may have been the last thing to occur, which means
196 * the primary plane may be full blue instead of the red it's
200 test_plane(data_t *data, igt_output_t *output, enum pipe pipe, enum igt_plane plane)
202 struct igt_fb red_fb, green_fb, blue_fb;
203 drmModeModeInfo *mode;
204 igt_plane_t *primary, *sprite;
205 igt_crc_t ref_crc, crc;
208 igt_output_set_pipe(output, pipe);
209 igt_display_commit(&data->display);
211 if (!output->valid) {
212 igt_output_set_pipe(output, PIPE_ANY);
213 igt_display_commit(&data->display);
217 primary = igt_output_get_plane(output, 0);
218 sprite = igt_output_get_plane(output, plane);
220 mode = igt_output_get_mode(output);
221 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
226 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
231 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
238 * Make sure these buffers are suited for display use
239 * because most of the modeset operations must be fast
242 igt_plane_set_fb(primary, &blue_fb);
243 igt_display_commit(&data->display);
244 igt_plane_set_fb(sprite, &green_fb);
245 igt_display_commit(&data->display);
246 igt_plane_set_fb(sprite, NULL);
247 igt_display_commit(&data->display);
250 igt_pipe_crc_free(data->pipe_crc);
251 data->pipe_crc = igt_pipe_crc_new(pipe, INTEL_PIPE_CRC_SOURCE_AUTO);
252 if (!data->pipe_crc) {
253 igt_info("auto crc not supported on this connector with crtc %i\n",
256 igt_plane_set_fb(primary, NULL);
257 igt_plane_set_fb(sprite, NULL);
258 igt_output_set_pipe(output, PIPE_ANY);
259 igt_display_commit(&data->display);
261 igt_remove_fb(data->drm_fd, &red_fb);
262 igt_remove_fb(data->drm_fd, &green_fb);
263 igt_remove_fb(data->drm_fd, &blue_fb);
268 /* set red fb and grab reference crc */
269 igt_plane_set_fb(primary, &red_fb);
270 igt_display_commit(&data->display);
271 igt_pipe_crc_collect_crc(data->pipe_crc, &ref_crc);
273 ret = drmModeSetCrtc(data->drm_fd, output->config.crtc->crtc_id,
274 blue_fb.fb_id, 0, 0, &output->id, 1,
276 igt_assert(ret == 0);
278 make_gpu_busy(data, blue_fb.gem_handle);
280 data->flip_done = false;
281 ret = drmModePageFlip(data->drm_fd, output->config.crtc->crtc_id,
282 blue_fb.fb_id, DRM_MODE_PAGE_FLIP_EVENT, data);
283 igt_assert(ret == 0);
286 * Toggle a fullscreen sprite on and back off. This will result
287 * in the primary plane getting disabled and re-enbled, and that
288 * leads to mmio flips. The driver may then mistake the flip done
289 * interrupts from the mmio flips as the flip done interrupts for
290 * the CS flip, and hence subsequent mmio flips won't wait for the
291 * CS flips like they should.
293 ret = drmModeSetPlane(data->drm_fd,
294 sprite->drm_plane->plane_id,
295 output->config.crtc->crtc_id,
297 0, 0, mode->hdisplay, mode->vdisplay,
298 0, 0, mode->hdisplay << 16, mode->vdisplay << 16);
299 igt_assert(ret == 0);
300 ret = drmModeSetPlane(data->drm_fd,
301 sprite->drm_plane->plane_id,
302 output->config.crtc->crtc_id,
306 igt_assert(ret == 0);
309 * Set primary plane to red fb. This should wait for the CS flip
310 * to complete. But if the kernel mistook the flip done interrupt
311 * from the mmio flip as the flip done from the CS flip, this will
312 * not wait for anything. And hence the the CS flip will actually
313 * occur after this mmio flip.
315 ret = drmModeSetCrtc(data->drm_fd, output->config.crtc->crtc_id,
316 red_fb.fb_id, 0, 0, &output->id, 1,
318 igt_assert(ret == 0);
320 /* Make sure the flip has been executed */
321 wait_for_flip(data, blue_fb.gem_handle);
323 /* Grab crc and compare with the extected result */
324 igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
326 igt_plane_set_fb(primary, NULL);
327 igt_display_commit(&data->display);
329 igt_remove_fb(data->drm_fd, &red_fb);
330 igt_remove_fb(data->drm_fd, &green_fb);
331 igt_remove_fb(data->drm_fd, &blue_fb);
333 igt_pipe_crc_free(data->pipe_crc);
334 data->pipe_crc = NULL;
336 igt_output_set_pipe(output, PIPE_ANY);
337 igt_display_commit(&data->display);
339 igt_assert(igt_crc_equal(&ref_crc, &crc));
345 * 1. set primary plane to full red
346 * 2. grab a reference crc
347 * 3. set primary plane to full green
349 * 5. pan primary plane a bit (to cause a mmio flip w/o vblank wait)
350 * 6. queue lots of GPU activity to delay the subsequent page flip
351 * 6. queue a page flip to a blue fb
352 * 7. set primary plane to red fb
353 * 8. wait for GPU to finish
354 * 9. compare current crc with reference crc
356 * We expect the primary plane to display full red at the end.
357 * If the previously schedule primary plane pan operation has interfered
358 * with the following page flip, the driver may have mistakenly completed
359 * the flip before it was executed by the CS, and hence the subsequent mmio
360 * flips may have overtaken it. So once we've finished everything
361 * the CS flip may have been the last thing to occur, which means
362 * the primary plane may be full blue instead of the red it's
366 test_crtc(data_t *data, igt_output_t *output, enum pipe pipe)
368 struct igt_fb red_fb, green_fb, blue_fb;
369 drmModeModeInfo *mode;
370 igt_plane_t *primary;
371 igt_crc_t ref_crc, crc;
374 igt_output_set_pipe(output, pipe);
375 igt_display_commit(&data->display);
377 if (!output->valid) {
378 igt_output_set_pipe(output, PIPE_ANY);
379 igt_display_commit(&data->display);
383 primary = igt_output_get_plane(output, 0);
385 mode = igt_output_get_mode(output);
386 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay+1,
391 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay+1,
396 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay+1,
403 * Make sure these buffers are suited for display use
404 * because most of the modeset operations must be fast
407 igt_plane_set_fb(primary, &green_fb);
408 igt_display_commit(&data->display);
409 igt_plane_set_fb(primary, &blue_fb);
410 igt_display_commit(&data->display);
413 igt_pipe_crc_free(data->pipe_crc);
414 data->pipe_crc = igt_pipe_crc_new(pipe, INTEL_PIPE_CRC_SOURCE_AUTO);
415 if (!data->pipe_crc) {
416 igt_info("auto crc not supported on this connector with crtc %i\n",
419 igt_plane_set_fb(primary, NULL);
420 igt_output_set_pipe(output, PIPE_ANY);
421 igt_display_commit(&data->display);
423 igt_remove_fb(data->drm_fd, &red_fb);
424 igt_remove_fb(data->drm_fd, &green_fb);
425 igt_remove_fb(data->drm_fd, &blue_fb);
430 /* set red fb and grab reference crc */
431 igt_plane_set_fb(primary, &red_fb);
432 igt_display_commit(&data->display);
433 igt_pipe_crc_collect_crc(data->pipe_crc, &ref_crc);
436 * Further down we need to issue an mmio flip w/o the kernel
437 * waiting for vblank. The easiest way is to just pan within
438 * the same FB. So pan away a bit here, and later we undo this
439 * with another pan which will result in the desired mmio flip.
441 ret = drmModeSetCrtc(data->drm_fd, output->config.crtc->crtc_id,
442 green_fb.fb_id, 0, 1, &output->id, 1,
444 igt_assert(ret == 0);
447 * Make it more likely that the CS flip has been submitted into the
448 * ring by the time the mmio flip from the drmModeSetCrtc() below
449 * completes. The driver will then mistake the flip done interrupt
450 * from the mmio flip as the flip done interrupt from the CS flip.
452 igt_wait_for_vblank(data->drm_fd, pipe);
454 /* now issue the mmio flip w/o vblank waits in the kernel, ie. pan a bit */
455 ret = drmModeSetCrtc(data->drm_fd, output->config.crtc->crtc_id,
456 green_fb.fb_id, 0, 0, &output->id, 1,
458 igt_assert(ret == 0);
460 make_gpu_busy(data, blue_fb.gem_handle);
463 * Submit the CS flip. The commands must be emitted into the ring
464 * before the mmio flip from the panning operation completes.
466 data->flip_done = false;
467 ret = drmModePageFlip(data->drm_fd, output->config.crtc->crtc_id,
468 blue_fb.fb_id, DRM_MODE_PAGE_FLIP_EVENT, data);
469 igt_assert(ret == 0);
472 * Set primary plane to red fb. This should wait for the CS flip
473 * to complete. But if the kernel mistook the flip done interrupt
474 * from the mmio flip as the flip done from the CS flip, this will
475 * not wait for anything. And hence the the CS flip will actually
476 * occur after this mmio flip.
478 ret = drmModeSetCrtc(data->drm_fd, output->config.crtc->crtc_id,
479 red_fb.fb_id, 0, 0, &output->id, 1,
481 igt_assert(ret == 0);
483 /* Make sure the flip has been executed */
484 wait_for_flip(data, blue_fb.gem_handle);
486 /* Grab crc and compare with the extected result */
487 igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
489 igt_plane_set_fb(primary, NULL);
490 igt_display_commit(&data->display);
492 igt_remove_fb(data->drm_fd, &red_fb);
493 igt_remove_fb(data->drm_fd, &green_fb);
494 igt_remove_fb(data->drm_fd, &blue_fb);
496 igt_pipe_crc_free(data->pipe_crc);
497 data->pipe_crc = NULL;
499 igt_output_set_pipe(output, PIPE_ANY);
500 igt_display_commit(&data->display);
502 igt_assert(igt_crc_equal(&ref_crc, &crc));
508 run_plane_test_for_pipe(data_t *data, enum pipe pipe)
510 igt_output_t *output;
511 enum igt_plane plane = 1; /* testing with one sprite is enough */
514 igt_require(data->display.pipes[pipe].n_planes > 2);
516 for_each_connected_output(&data->display, output) {
517 if (test_plane(data, output, pipe, plane))
521 igt_require_f(valid_tests, "no valid crtc/connector combinations found\n");
525 run_crtc_test_for_pipe(data_t *data, enum pipe pipe)
527 igt_output_t *output;
530 for_each_connected_output(&data->display, output) {
531 if (test_crtc(data, output, pipe))
535 igt_require_f(valid_tests, "no valid crtc/connector combinations found\n");
544 igt_skip_on_simulation();
547 data.drm_fd = drm_open_any();
549 igt_set_vt_graphics_mode();
551 data.devid = intel_get_drm_devid(data.drm_fd);
553 igt_require_pipe_crc();
554 igt_display_init(&data.display, data.drm_fd);
556 data.bufmgr = drm_intel_bufmgr_gem_init(data.drm_fd, 4096);
557 igt_assert(data.bufmgr);
558 drm_intel_bufmgr_gem_enable_reuse(data.bufmgr);
560 data.busy_bo = drm_intel_bo_alloc(data.bufmgr, "bo",
562 gem_set_tiling(data.drm_fd, data.busy_bo->handle, 0, 4096);
565 igt_subtest_f("setplane_vs_cs_flip") {
566 for (pipe = 0; pipe < data.display.n_pipes; pipe++)
567 run_plane_test_for_pipe(&data, pipe);
570 igt_subtest_f("setcrtc_vs_cs_flip") {
571 for (pipe = 0; pipe < data.display.n_pipes; pipe++)
572 run_crtc_test_for_pipe(&data, pipe);
576 drm_intel_bo_unreference(data.busy_bo);
577 drm_intel_bufmgr_destroy(data.bufmgr);
578 igt_display_fini(&data.display);