09396a9d3b1c8ca0056b66b596e3536d49b62989
[platform/upstream/intel-gpu-tools.git] / tests / kms_mmio_vs_cs_flip.c
1 /*
2  * Copyright © 2014 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 #include <errno.h>
25 #include <stdbool.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <time.h>
29
30 #include "drmtest.h"
31 #include "igt_debugfs.h"
32 #include "igt_kms.h"
33 #include "intel_chipset.h"
34 #include "ioctl_wrappers.h"
35
36 typedef struct {
37         int drm_fd;
38         igt_display_t display;
39         igt_pipe_crc_t *pipe_crc;
40         drm_intel_bufmgr *bufmgr;
41         drm_intel_bo *busy_bo;
42         uint32_t devid;
43         bool flip_done;
44 } data_t;
45
46 static void exec_nop(data_t *data, uint32_t handle, unsigned int ring)
47 {
48         struct intel_batchbuffer *batch;
49         drm_intel_bo *bo;
50
51         batch = intel_batchbuffer_alloc(data->bufmgr, data->devid);
52         igt_assert(batch);
53
54         bo = gem_handle_to_libdrm_bo(data->bufmgr, data->drm_fd, "", handle);
55         igt_assert(bo);
56
57         /* add relocs to make sure the kernel will think we write to dst */
58         BEGIN_BATCH(4);
59         OUT_BATCH(MI_BATCH_BUFFER_END);
60         OUT_BATCH(MI_NOOP);
61         OUT_RELOC(bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
62         OUT_BATCH(MI_NOOP);
63         ADVANCE_BATCH();
64
65         intel_batchbuffer_flush_on_ring(batch, ring);
66         intel_batchbuffer_free(batch);
67
68         drm_intel_bo_unreference(bo);
69 }
70
71 static void exec_blt(data_t *data)
72 {
73         struct intel_batchbuffer *batch;
74         int w, h, pitch, i;
75
76         batch = intel_batchbuffer_alloc(data->bufmgr, data->devid);
77         igt_assert(batch);
78
79         w = 8192;
80         h = data->busy_bo->size / (8192 * 4);
81         pitch = w * 4;
82
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 */
87                           pitch);
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);
93                 OUT_BATCH(pitch);
94                 OUT_RELOC(data->busy_bo, I915_GEM_DOMAIN_RENDER, 0, 0);
95                 BLIT_RELOC_UDW(data->devid);
96                 ADVANCE_BATCH();
97         }
98
99         intel_batchbuffer_flush(batch);
100         intel_batchbuffer_free(batch);
101 }
102
103 static void page_flip_handler(int fd, unsigned int frame, unsigned int sec,
104                               unsigned int usec, void *_data)
105 {
106         data_t *data = _data;
107
108         data->flip_done = true;
109 }
110
111 static void wait_for_flip(data_t *data, uint32_t flip_handle)
112 {
113         struct timeval timeout = {
114                 .tv_sec = 3,
115                 .tv_usec = 0,
116         };
117         drmEventContext evctx = {
118                 .version = DRM_EVENT_CONTEXT_VERSION,
119                 .page_flip_handler = page_flip_handler,
120         };
121         fd_set fds;
122
123         FD_ZERO(&fds);
124         FD_SET(data->drm_fd, &fds);
125
126         while (!data->flip_done) {
127                 int ret = select(data->drm_fd + 1, &fds, NULL, NULL, &timeout);
128
129                 if (ret < 0 && errno == EINTR)
130                         continue;
131
132                 igt_assert(ret >= 0);
133
134                 do_or_die(drmHandleEvent(data->drm_fd, &evctx));
135         }
136
137         /*
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.
141          */
142         if (IS_GEN7(data->devid) || IS_GEN8(data->devid))
143                 exec_nop(data, flip_handle, I915_EXEC_BLT);
144         else
145                 exec_nop(data, flip_handle, I915_EXEC_RENDER);
146         gem_sync(data->drm_fd, flip_handle);
147 }
148
149 static void make_gpu_busy(data_t *data, uint32_t flip_handle)
150 {
151         /*
152          * Make sure flip_handle has been used on the blt ring.
153          * This should make the flip use the same ring on gen7+.
154          */
155         if (IS_GEN7(data->devid) || IS_GEN8(data->devid))
156                 exec_nop(data, flip_handle, I915_EXEC_BLT);
157
158         /*
159          * Add a pile commands to the ring.  The flip will be
160          * stuck behing these commands and hence gets delayed
161          * significantly.
162          */
163         exec_blt(data);
164
165         /*
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).
169          *
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.
174          */
175         if (HAS_BLT_RING(data->devid))
176                 exec_nop(data, data->busy_bo->handle, I915_EXEC_RENDER);
177 }
178
179 /*
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
189  *
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
197  * supposed to be.
198  */
199 static bool
200 test_plane(data_t *data, igt_output_t *output, enum pipe pipe, enum igt_plane plane)
201 {
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;
206         int ret;
207
208         igt_output_set_pipe(output, pipe);
209         igt_display_commit(&data->display);
210
211         if (!output->valid) {
212                 igt_output_set_pipe(output, PIPE_ANY);
213                 igt_display_commit(&data->display);
214                 return false;
215         }
216
217         primary = igt_output_get_plane(output, 0);
218         sprite = igt_output_get_plane(output, plane);
219
220         mode = igt_output_get_mode(output);
221         igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
222                             DRM_FORMAT_XRGB8888,
223                             I915_TILING_NONE,
224                             1.0, 0.0, 0.0,
225                             &red_fb);
226         igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
227                             DRM_FORMAT_XRGB8888,
228                             I915_TILING_NONE,
229                             0.0, 1.0, 0.0,
230                             &green_fb);
231         igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
232                             DRM_FORMAT_XRGB8888,
233                             I915_TILING_NONE,
234                             0.0, 0.0, 1.0,
235                             &blue_fb);
236
237         /*
238          * Make sure these buffers are suited for display use
239          * because most of the modeset operations must be fast
240          * later on.
241          */
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);
248
249         if (data->pipe_crc)
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",
254                          pipe);
255
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);
260
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);
264
265                 return false;
266         }
267
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);
272
273         ret = drmModeSetCrtc(data->drm_fd, output->config.crtc->crtc_id,
274                              blue_fb.fb_id, 0, 0, &output->id, 1,
275                              mode);
276         igt_assert(ret == 0);
277
278         make_gpu_busy(data, blue_fb.gem_handle);
279
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);
284
285         /*
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.
292          */
293         ret = drmModeSetPlane(data->drm_fd,
294                               sprite->drm_plane->plane_id,
295                               output->config.crtc->crtc_id,
296                               green_fb.fb_id, 0,
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,
303                               0, 0,
304                               0, 0, 0, 0,
305                               0, 0, 0, 0);
306         igt_assert(ret == 0);
307
308         /*
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.
314          */
315         ret = drmModeSetCrtc(data->drm_fd, output->config.crtc->crtc_id,
316                              red_fb.fb_id, 0, 0, &output->id, 1,
317                              mode);
318         igt_assert(ret == 0);
319
320         /* Make sure the flip has been executed */
321         wait_for_flip(data, blue_fb.gem_handle);
322
323         /* Grab crc and compare with the extected result */
324         igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
325
326         igt_plane_set_fb(primary, NULL);
327         igt_display_commit(&data->display);
328
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);
332
333         igt_pipe_crc_free(data->pipe_crc);
334         data->pipe_crc = NULL;
335
336         igt_output_set_pipe(output, PIPE_ANY);
337         igt_display_commit(&data->display);
338
339         igt_assert(igt_crc_equal(&ref_crc, &crc));
340
341         return true;
342 }
343
344 /*
345  * 1. set primary plane to full red
346  * 2. grab a reference crc
347  * 3. set primary plane to full green
348  * 4. wait for vblank
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
355  *
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
363  * supposed to be.
364  */
365 static bool
366 test_crtc(data_t *data, igt_output_t *output, enum pipe pipe)
367 {
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;
372         int ret;
373
374         igt_output_set_pipe(output, pipe);
375         igt_display_commit(&data->display);
376
377         if (!output->valid) {
378                 igt_output_set_pipe(output, PIPE_ANY);
379                 igt_display_commit(&data->display);
380                 return false;
381         }
382
383         primary = igt_output_get_plane(output, 0);
384
385         mode = igt_output_get_mode(output);
386         igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay+1,
387                             DRM_FORMAT_XRGB8888,
388                             I915_TILING_NONE,
389                             1.0, 0.0, 0.0,
390                             &red_fb);
391         igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay+1,
392                             DRM_FORMAT_XRGB8888,
393                             I915_TILING_NONE,
394                             0.0, 0.0, 1.0,
395                             &blue_fb);
396         igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay+1,
397                             DRM_FORMAT_XRGB8888,
398                             I915_TILING_NONE,
399                             0.0, 1.0, 0.0,
400                             &green_fb);
401
402         /*
403          * Make sure these buffers are suited for display use
404          * because most of the modeset operations must be fast
405          * later on.
406          */
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);
411
412         if (data->pipe_crc)
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",
417                          pipe);
418
419                 igt_plane_set_fb(primary, NULL);
420                 igt_output_set_pipe(output, PIPE_ANY);
421                 igt_display_commit(&data->display);
422
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);
426
427                 return false;
428         }
429
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);
434
435         /*
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.
440          */
441         ret = drmModeSetCrtc(data->drm_fd, output->config.crtc->crtc_id,
442                              green_fb.fb_id, 0, 1, &output->id, 1,
443                              mode);
444         igt_assert(ret == 0);
445
446         /*
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.
451          */
452         igt_wait_for_vblank(data->drm_fd, pipe);
453
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,
457                              mode);
458         igt_assert(ret == 0);
459
460         make_gpu_busy(data, blue_fb.gem_handle);
461
462         /*
463          * Submit the CS flip. The commands must be emitted into the ring
464          * before the mmio flip from the panning operation completes.
465          */
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);
470
471         /*
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.
477          */
478         ret = drmModeSetCrtc(data->drm_fd, output->config.crtc->crtc_id,
479                              red_fb.fb_id, 0, 0, &output->id, 1,
480                              mode);
481         igt_assert(ret == 0);
482
483         /* Make sure the flip has been executed */
484         wait_for_flip(data, blue_fb.gem_handle);
485
486         /* Grab crc and compare with the extected result */
487         igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
488
489         igt_plane_set_fb(primary, NULL);
490         igt_display_commit(&data->display);
491
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);
495
496         igt_pipe_crc_free(data->pipe_crc);
497         data->pipe_crc = NULL;
498
499         igt_output_set_pipe(output, PIPE_ANY);
500         igt_display_commit(&data->display);
501
502         igt_assert(igt_crc_equal(&ref_crc, &crc));
503
504         return true;
505 }
506
507 static void
508 run_plane_test_for_pipe(data_t *data, enum pipe pipe)
509 {
510         igt_output_t *output;
511         enum igt_plane plane = 1; /* testing with one sprite is enough */
512         int valid_tests = 0;
513
514         igt_require(data->display.pipes[pipe].n_planes > 2);
515
516         for_each_connected_output(&data->display, output) {
517                 if (test_plane(data, output, pipe, plane))
518                         valid_tests++;
519         }
520
521         igt_require_f(valid_tests, "no valid crtc/connector combinations found\n");
522 }
523
524 static void
525 run_crtc_test_for_pipe(data_t *data, enum pipe pipe)
526 {
527         igt_output_t *output;
528         int valid_tests = 0;
529
530         for_each_connected_output(&data->display, output) {
531                 if (test_crtc(data, output, pipe))
532                         valid_tests++;
533         }
534
535         igt_require_f(valid_tests, "no valid crtc/connector combinations found\n");
536 }
537
538 static data_t data;
539
540 igt_main
541 {
542         int pipe;
543
544         igt_skip_on_simulation();
545
546         igt_fixture {
547                 data.drm_fd = drm_open_any();
548
549                 kmstest_set_vt_graphics_mode();
550
551                 data.devid = intel_get_drm_devid(data.drm_fd);
552
553                 igt_require_pipe_crc();
554                 igt_display_init(&data.display, data.drm_fd);
555
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);
559
560                 data.busy_bo = drm_intel_bo_alloc(data.bufmgr, "bo",
561                                                   64*1024*1024, 4096);
562                 gem_set_tiling(data.drm_fd, data.busy_bo->handle, 0, 4096);
563         }
564
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);
568         }
569
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);
573         }
574
575         igt_fixture {
576                 drm_intel_bo_unreference(data.busy_bo);
577                 drm_intel_bufmgr_destroy(data.bufmgr);
578                 igt_display_fini(&data.display);
579         }
580 }