blob: d6ef1f1770b233666803b8638c9d6ce0e67fecc0 [file] [log] [blame]
Chris Wilsonfb292f42016-08-23 09:33:19 +01001/*
2 * Copyright © 2016 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 "igt.h"
25
26#include <sys/poll.h>
27#include <signal.h>
28#include <time.h>
29
30IGT_TEST_DESCRIPTION("Basic check of KMS ABI with busy framebuffers.");
31
32#define FRAME_TIME 16 /* milleseconds */
33#define TIMEOUT (6*16)
34
35static igt_output_t *
36set_fb_on_crtc(igt_display_t *dpy, int pipe, struct igt_fb *fb)
37{
38 igt_output_t *output;
39
40 for_each_valid_output_on_pipe(dpy, pipe, output) {
41 drmModeModeInfoPtr mode;
42 igt_plane_t *primary;
43
44 if (output->pending_crtc_idx_mask)
45 continue;
46
47 igt_output_set_pipe(output, pipe);
48 mode = igt_output_get_mode(output);
49
50 igt_create_pattern_fb(dpy->drm_fd,
51 mode->hdisplay, mode->vdisplay,
52 DRM_FORMAT_XRGB8888,
53 LOCAL_I915_FORMAT_MOD_X_TILED,
54 fb);
55
Robert Foss2b405b42017-01-10 18:31:20 -050056 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
Chris Wilsonfb292f42016-08-23 09:33:19 +010057 igt_plane_set_fb(primary, fb);
58
59 return output;
60 }
61
62 return NULL;
63}
64
65static void do_cleanup_display(igt_display_t *dpy)
66{
67 enum pipe pipe;
68 igt_output_t *output;
69 igt_plane_t *plane;
70
71 for_each_pipe(dpy, pipe)
72 for_each_plane_on_pipe(dpy, pipe, plane)
73 igt_plane_set_fb(plane, NULL);
74
75 for_each_connected_output(dpy, output)
76 igt_output_set_pipe(output, PIPE_NONE);
77
78 igt_display_commit2(dpy, dpy->is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY);
79}
80
Chris Wilsonfb292f42016-08-23 09:33:19 +010081static void sighandler(int sig)
82{
83}
84
85static void flip_to_fb(igt_display_t *dpy, int pipe,
Maarten Lankhorst24bfa3e2017-01-26 11:35:50 +010086 igt_output_t *output,
Chris Wilsonfb292f42016-08-23 09:33:19 +010087 struct igt_fb *fb, unsigned ring,
Maarten Lankhorst24bfa3e2017-01-26 11:35:50 +010088 const char *name, bool modeset)
Chris Wilsonfb292f42016-08-23 09:33:19 +010089{
90 struct pollfd pfd = { .fd = dpy->drm_fd, .events = POLLIN };
91 struct timespec tv = { 1, 0 };
92 struct drm_event_vblank ev;
Maarten Lankhorst24bfa3e2017-01-26 11:35:50 +010093
Abdiel Janulgue0eef0402016-11-11 19:25:21 +020094 igt_spin_t *t = igt_spin_batch_new(dpy->drm_fd, ring, fb->gem_handle);
Maarten Lankhorst0f1db812017-02-06 16:06:56 +010095
96 if (modeset) {
97 /*
98 * We want to check that a modeset actually waits for the
99 * spin batch to complete, but we keep a bigger timeout for
100 * disable than required for flipping.
101 *
102 * As a result, the GPU reset code may kick in, which we neuter
103 * here to be sure there's no premature completion.
104 */
105 igt_set_module_param_int("enable_hangcheck", 0);
106 }
107
Chris Wilsonfb292f42016-08-23 09:33:19 +0100108 igt_fork(child, 1) {
109 igt_assert(gem_bo_busy(dpy->drm_fd, fb->gem_handle));
Maarten Lankhorst24bfa3e2017-01-26 11:35:50 +0100110 if (!modeset)
111 do_or_die(drmModePageFlip(dpy->drm_fd,
112 dpy->pipes[pipe].crtc_id, fb->fb_id,
113 DRM_MODE_PAGE_FLIP_EVENT, fb));
114 else {
Robert Foss2b405b42017-01-10 18:31:20 -0500115 igt_plane_set_fb(igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY), fb);
Maarten Lankhorst24bfa3e2017-01-26 11:35:50 +0100116 igt_output_set_pipe(output, PIPE_NONE);
117 igt_display_commit_atomic(dpy,
118 DRM_MODE_ATOMIC_NONBLOCK |
119 DRM_MODE_PAGE_FLIP_EVENT |
120 DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
121 }
122
Chris Wilsonfb292f42016-08-23 09:33:19 +0100123 kill(getppid(), SIGALRM);
Chris Wilson3e7a4e02016-12-01 15:15:40 +0000124 igt_assert(gem_bo_busy(dpy->drm_fd, fb->gem_handle));
Maarten Lankhorst0f1db812017-02-06 16:06:56 +0100125 igt_assert_f(poll(&pfd, 1, modeset ? 8500 : TIMEOUT) == 0,
Chris Wilson3e7a4e02016-12-01 15:15:40 +0000126 "flip completed whilst %s was busy [%d]\n",
127 name, gem_bo_busy(dpy->drm_fd, fb->gem_handle));
Chris Wilsonfb292f42016-08-23 09:33:19 +0100128 }
Maarten Lankhorst0f1db812017-02-06 16:06:56 +0100129
Chris Wilsonfb292f42016-08-23 09:33:19 +0100130 igt_assert_f(nanosleep(&tv, NULL) == -1,
131 "flip to %s blocked waiting for busy fb", name);
Maarten Lankhorst0f1db812017-02-06 16:06:56 +0100132
Chris Wilsonfb292f42016-08-23 09:33:19 +0100133 igt_waitchildren();
Maarten Lankhorst0f1db812017-02-06 16:06:56 +0100134
135 if (!modeset) {
136 tv.tv_sec = 0;
137 tv.tv_nsec = (2 * TIMEOUT) * 1000000ULL;
138 nanosleep(&tv, NULL);
139 }
140
141 igt_spin_batch_end(t);
142
Chris Wilsonfb292f42016-08-23 09:33:19 +0100143 igt_assert(read(dpy->drm_fd, &ev, sizeof(ev)) == sizeof(ev));
144 igt_assert(poll(&pfd, 1, 0) == 0);
Abdiel Janulgue0eef0402016-11-11 19:25:21 +0200145
Maarten Lankhorst24bfa3e2017-01-26 11:35:50 +0100146 if (modeset) {
Maarten Lankhorst0f1db812017-02-06 16:06:56 +0100147 igt_set_module_param_int("enable_hangcheck", 1);
Maarten Lankhorst24bfa3e2017-01-26 11:35:50 +0100148 dpy->pipes[pipe].mode_blob = 0;
149 igt_output_set_pipe(output, pipe);
150 igt_display_commit2(dpy, COMMIT_ATOMIC);
151 }
152
Abdiel Janulgue0eef0402016-11-11 19:25:21 +0200153 igt_spin_batch_free(dpy->drm_fd, t);
Chris Wilsonfb292f42016-08-23 09:33:19 +0100154}
155
Maarten Lankhorst24bfa3e2017-01-26 11:35:50 +0100156static void test_flip(igt_display_t *dpy, unsigned ring, int pipe, bool modeset)
Chris Wilsonfb292f42016-08-23 09:33:19 +0100157{
158 struct igt_fb fb[2];
159 int warmup[] = { 0, 1, 0, -1 };
Maarten Lankhorst24bfa3e2017-01-26 11:35:50 +0100160 igt_output_t *output;
161
162 if (modeset)
163 igt_require(dpy->is_atomic);
Chris Wilsonfb292f42016-08-23 09:33:19 +0100164
165 signal(SIGALRM, sighandler);
166
Maarten Lankhorst24bfa3e2017-01-26 11:35:50 +0100167 igt_require((output = set_fb_on_crtc(dpy, pipe, &fb[0])));
Chris Wilsonfb292f42016-08-23 09:33:19 +0100168 igt_display_commit2(dpy, COMMIT_LEGACY);
169
170 igt_create_pattern_fb(dpy->drm_fd,
171 fb[0].width, fb[0].height,
172 DRM_FORMAT_XRGB8888,
173 LOCAL_I915_FORMAT_MOD_X_TILED,
174 &fb[1]);
175
176 /* Bind both fb to the display (such that they are ready for future
177 * flips without stalling for the bind) leaving fb[0] as bound.
178 */
179 for (int i = 0; warmup[i] != -1; i++) {
180 struct drm_event_vblank ev;
181
182 do_or_die(drmModePageFlip(dpy->drm_fd,
183 dpy->pipes[pipe].crtc_id,
184 fb[warmup[i]].fb_id,
185 DRM_MODE_PAGE_FLIP_EVENT,
186 &fb[warmup[i]]));
187 igt_assert(read(dpy->drm_fd, &ev, sizeof(ev)) == sizeof(ev));
188 }
189
190 /* Make the frontbuffer busy and try to flip to itself */
Maarten Lankhorst24bfa3e2017-01-26 11:35:50 +0100191 flip_to_fb(dpy, pipe, output, &fb[0], ring, "fb[0]", modeset);
Chris Wilsonfb292f42016-08-23 09:33:19 +0100192
193 /* Repeat for flip to second buffer */
Maarten Lankhorst24bfa3e2017-01-26 11:35:50 +0100194 flip_to_fb(dpy, pipe, output, &fb[1], ring, "fb[1]", modeset);
Chris Wilsonfb292f42016-08-23 09:33:19 +0100195
196 do_cleanup_display(dpy);
197 igt_remove_fb(dpy->drm_fd, &fb[1]);
198 igt_remove_fb(dpy->drm_fd, &fb[0]);
199
200 signal(SIGALRM, SIG_DFL);
201}
202
Maarten Lankhorst24bfa3e2017-01-26 11:35:50 +0100203static void test_atomic_commit_hang(igt_display_t *dpy, igt_plane_t *primary,
204 struct igt_fb *busy_fb, unsigned ring,
205 bool completes_early)
206{
207 igt_spin_t *t = igt_spin_batch_new(dpy->drm_fd, ring, busy_fb->gem_handle);
208 struct pollfd pfd = { .fd = dpy->drm_fd, .events = POLLIN };
209 unsigned flags = 0;
210 struct drm_event_vblank ev;
211
212 flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
213 flags |= DRM_MODE_ATOMIC_NONBLOCK;
214 flags |= DRM_MODE_PAGE_FLIP_EVENT;
215
216 igt_display_commit_atomic(dpy, flags, NULL);
217
218 igt_fork(child, 1) {
219 /*
220 * bit of a hack, just set atomic commit to NULL fb to make sure
221 * that we don't wait for the new update to complete.
222 */
223 igt_plane_set_fb(primary, NULL);
224 igt_display_commit_atomic(dpy, 0, NULL);
225
226 if (completes_early)
227 igt_assert(gem_bo_busy(dpy->drm_fd, busy_fb->gem_handle));
228 else
229 igt_fail_on(gem_bo_busy(dpy->drm_fd, busy_fb->gem_handle));
230
231 igt_assert_f(poll(&pfd, 1, 1) > 0,
232 "nonblocking update completed whilst fb[%d] was still busy [%d]\n",
233 busy_fb->fb_id, gem_bo_busy(dpy->drm_fd, busy_fb->gem_handle));
234 }
235
236 igt_waitchildren();
237
238 igt_assert(read(dpy->drm_fd, &ev, sizeof(ev)) == sizeof(ev));
239
240 igt_spin_batch_end(t);
241}
242
243static void test_hang(igt_display_t *dpy, unsigned ring,
244 enum pipe pipe, bool modeset, bool hang_newfb)
245{
246 struct igt_fb fb[2];
247 igt_output_t *output;
248 igt_plane_t *primary;
249
250 igt_require((output = set_fb_on_crtc(dpy, pipe, &fb[0])));
251 igt_display_commit2(dpy, COMMIT_ATOMIC);
Robert Foss2b405b42017-01-10 18:31:20 -0500252 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
Maarten Lankhorst24bfa3e2017-01-26 11:35:50 +0100253
254 igt_create_pattern_fb(dpy->drm_fd,
255 fb[0].width, fb[0].height,
256 DRM_FORMAT_XRGB8888,
257 LOCAL_I915_FORMAT_MOD_X_TILED,
258 &fb[1]);
259
260 if (modeset) {
261 /* Test modeset disable with hang */
262 igt_output_set_pipe(output, PIPE_NONE);
263 igt_plane_set_fb(primary, &fb[1]);
264 test_atomic_commit_hang(dpy, primary, &fb[hang_newfb], ring, hang_newfb);
265
266 /* Test modeset enable with hang */
267 igt_plane_set_fb(primary, &fb[0]);
268 igt_output_set_pipe(output, pipe);
269 test_atomic_commit_hang(dpy, primary, &fb[!hang_newfb], ring, hang_newfb);
270 } else {
271 /*
272 * Test what happens with a single hanging pageflip.
273 * This always completes early, because we have some
274 * timeouts taking care of it.
275 */
276 igt_plane_set_fb(primary, &fb[1]);
277 test_atomic_commit_hang(dpy, primary, &fb[hang_newfb], ring, true);
278 }
279
280 do_cleanup_display(dpy);
281 igt_remove_fb(dpy->drm_fd, &fb[1]);
282 igt_remove_fb(dpy->drm_fd, &fb[0]);
283}
284
Chris Wilsonfb292f42016-08-23 09:33:19 +0100285igt_main
286{
Chris Wilson65a99872016-08-24 09:16:31 +0100287 igt_display_t display = { .drm_fd = -1, .n_pipes = I915_MAX_PIPES };
Chris Wilsonfb292f42016-08-23 09:33:19 +0100288 const struct intel_execution_engine *e;
289
290 igt_skip_on_simulation();
291
292 igt_fixture {
293 int fd = drm_open_driver_master(DRIVER_INTEL);
294
Chris Wilson2a7bd7a2017-03-08 14:34:34 +0000295 igt_require_gem(fd);
Chris Wilsonfb292f42016-08-23 09:33:19 +0100296 gem_require_mmap_wc(fd);
297
298 kmstest_set_vt_graphics_mode();
299 igt_display_init(&display, fd);
300 igt_require(display.n_pipes > 0);
301 }
302
303 /* XXX Extend to cover atomic rendering tests to all planes + legacy */
304
305 for (int n = 0; n < I915_MAX_PIPES; n++) {
306 errno = 0;
307
308 igt_fixture {
309 igt_skip_on(n >= display.n_pipes);
310 }
311
312 for (e = intel_execution_engines; e->name; e++) {
Chris Wilsonfb292f42016-08-23 09:33:19 +0100313 igt_subtest_f("%sflip-%s-%s",
314 e->exec_id == 0 ? "basic-" : "",
Chris Wilson65a99872016-08-24 09:16:31 +0100315 e->name, kmstest_pipe_name(n)) {
316 igt_require(gem_has_ring(display.drm_fd,
317 e->exec_id | e->flags));
318
Maarten Lankhorst24bfa3e2017-01-26 11:35:50 +0100319 test_flip(&display, e->exec_id | e->flags, n, false);
320 }
321 igt_subtest_f("%smodeset-%s-%s",
322 e->exec_id == 0 ? "basic-" : "",
323 e->name, kmstest_pipe_name(n)) {
324 igt_require(gem_has_ring(display.drm_fd,
325 e->exec_id | e->flags));
326
327 test_flip(&display, e->exec_id | e->flags, n, true);
328 }
329
330 igt_subtest_group {
331 igt_hang_t hang;
332
333 igt_fixture {
334 igt_require(display.is_atomic);
335
336 hang = igt_allow_hang(display.drm_fd, 0, 0);
337 }
338
339 igt_subtest_f("extended-pageflip-hang-oldfb-%s-%s",
340 e->name, kmstest_pipe_name(n)) {
341 igt_require(gem_has_ring(display.drm_fd,
342 e->exec_id | e->flags));
343
344 test_hang(&display, e->exec_id | e->flags, n, false, false);
345 }
346
347 igt_subtest_f("extended-pageflip-hang-newfb-%s-%s",
348 e->name, kmstest_pipe_name(n)) {
349 igt_require(gem_has_ring(display.drm_fd,
350 e->exec_id | e->flags));
351
352 test_hang(&display, e->exec_id | e->flags, n, false, true);
353 }
354
355 igt_subtest_f("extended-modeset-hang-oldfb-%s-%s",
356 e->name, kmstest_pipe_name(n)) {
357 igt_require(gem_has_ring(display.drm_fd,
358 e->exec_id | e->flags));
359
360 test_hang(&display, e->exec_id | e->flags, n, true, false);
361 }
362
363 igt_subtest_f("extended-modeset-hang-newfb-%s-%s",
364 e->name, kmstest_pipe_name(n)) {
365 igt_require(gem_has_ring(display.drm_fd,
366 e->exec_id | e->flags));
367
368 test_hang(&display, e->exec_id | e->flags, n, true, true);
369 }
370
371 igt_subtest_f("extended-modeset-hang-oldfb-with-reset-%s-%s",
372 e->name, kmstest_pipe_name(n)) {
373 igt_require(gem_has_ring(display.drm_fd,
374 e->exec_id | e->flags));
375 igt_set_module_param_int("force_reset_modeset_test", 1);
376
377 test_hang(&display, e->exec_id | e->flags, n, true, false);
378
379 igt_set_module_param_int("force_reset_modeset_test", 0);
380 }
381
382 igt_subtest_f("extended-modeset-hang-newfb-with-reset-%s-%s",
383 e->name, kmstest_pipe_name(n)) {
384 igt_require(gem_has_ring(display.drm_fd,
385 e->exec_id | e->flags));
386 igt_set_module_param_int("force_reset_modeset_test", 1);
387
388 test_hang(&display, e->exec_id | e->flags, n, true, true);
389
390 igt_set_module_param_int("force_reset_modeset_test", 0);
391 }
392
393 igt_fixture {
394 igt_disallow_hang(display.drm_fd, hang);
395 }
Chris Wilson65a99872016-08-24 09:16:31 +0100396 }
Chris Wilsonfb292f42016-08-23 09:33:19 +0100397 }
398 }
399
400 igt_fixture {
401 igt_display_fini(&display);
402 }
403}