1 /*
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
30 IGT_TEST_DESCRIPTION("Basic check of KMS ABI with busy framebuffers.");
31
32 static igt_output_t *
set_fb_on_crtc(igt_display_t * dpy,int pipe,struct igt_fb * fb)33 set_fb_on_crtc(igt_display_t *dpy, int pipe, struct igt_fb *fb)
34 {
35 drmModeModeInfoPtr mode;
36 igt_plane_t *primary;
37 igt_output_t *output;
38
39 output = igt_get_single_output_for_pipe(dpy, pipe);
40
41 igt_output_set_pipe(output, pipe);
42 mode = igt_output_get_mode(output);
43
44 igt_create_pattern_fb(dpy->drm_fd, mode->hdisplay, mode->vdisplay,
45 DRM_FORMAT_XRGB8888,
46 LOCAL_I915_FORMAT_MOD_X_TILED, fb);
47
48 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
49 igt_plane_set_fb(primary, fb);
50
51 return output;
52 }
53
do_cleanup_display(igt_display_t * dpy)54 static void do_cleanup_display(igt_display_t *dpy)
55 {
56 enum pipe pipe;
57 igt_output_t *output;
58 igt_plane_t *plane;
59
60 for_each_pipe(dpy, pipe)
61 for_each_plane_on_pipe(dpy, pipe, plane)
62 igt_plane_set_fb(plane, NULL);
63
64 for_each_connected_output(dpy, output)
65 igt_output_set_pipe(output, PIPE_NONE);
66
67 igt_display_commit2(dpy, dpy->is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY);
68 }
69
flip_to_fb(igt_display_t * dpy,int pipe,igt_output_t * output,struct igt_fb * fb,unsigned ring,const char * name,bool modeset)70 static void flip_to_fb(igt_display_t *dpy, int pipe,
71 igt_output_t *output,
72 struct igt_fb *fb, unsigned ring,
73 const char *name, bool modeset)
74 {
75 struct pollfd pfd = { .fd = dpy->drm_fd, .events = POLLIN };
76 const int timeout = modeset ? 8500 : 100;
77 struct drm_event_vblank ev;
78
79 igt_spin_t *t = igt_spin_new(dpy->drm_fd,
80 .engine = ring,
81 .dependency = fb->gem_handle);
82
83 if (modeset) {
84 /*
85 * We want to check that a modeset actually waits for the
86 * spin batch to complete, but we keep a bigger timeout for
87 * disable than required for flipping.
88 *
89 * As a result, the GPU reset code may kick in, which we neuter
90 * here to be sure there's no premature completion.
91 */
92 igt_set_module_param_int("enable_hangcheck", 0);
93 }
94
95 igt_fork(child, 1) {
96 igt_assert(gem_bo_busy(dpy->drm_fd, fb->gem_handle));
97 if (!modeset)
98 do_or_die(drmModePageFlip(dpy->drm_fd,
99 dpy->pipes[pipe].crtc_id, fb->fb_id,
100 DRM_MODE_PAGE_FLIP_EVENT, fb));
101 else {
102 igt_plane_set_fb(igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY), fb);
103 igt_output_set_pipe(output, PIPE_NONE);
104 igt_display_commit_atomic(dpy,
105 DRM_MODE_ATOMIC_NONBLOCK |
106 DRM_MODE_PAGE_FLIP_EVENT |
107 DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
108 }
109
110 igt_assert_f(poll(&pfd, 1, timeout) == 0,
111 "flip completed whilst %s was busy [%d]\n",
112 name, gem_bo_busy(dpy->drm_fd, fb->gem_handle));
113 igt_assert(gem_bo_busy(dpy->drm_fd, fb->gem_handle));
114 }
115
116 igt_waitchildren_timeout(5 * timeout,
117 "flip blocked waiting for busy bo\n");
118 igt_spin_end(t);
119
120 igt_assert(read(dpy->drm_fd, &ev, sizeof(ev)) == sizeof(ev));
121 igt_assert(poll(&pfd, 1, 0) == 0);
122
123 if (modeset) {
124 gem_quiescent_gpu(dpy->drm_fd);
125 igt_set_module_param_int("enable_hangcheck", 1);
126
127 /* Clear old mode blob. */
128 igt_pipe_refresh(dpy, pipe, true);
129
130 igt_output_set_pipe(output, pipe);
131 igt_display_commit2(dpy, COMMIT_ATOMIC);
132 }
133
134 igt_spin_free(dpy->drm_fd, t);
135 }
136
test_flip(igt_display_t * dpy,unsigned ring,int pipe,bool modeset)137 static void test_flip(igt_display_t *dpy, unsigned ring, int pipe, bool modeset)
138 {
139 struct igt_fb fb[2];
140 int warmup[] = { 0, 1, 0, -1 };
141 igt_output_t *output;
142
143 if (modeset)
144 igt_require(dpy->is_atomic);
145
146 output = set_fb_on_crtc(dpy, pipe, &fb[0]);
147 igt_display_commit2(dpy, COMMIT_LEGACY);
148
149 igt_create_pattern_fb(dpy->drm_fd,
150 fb[0].width, fb[0].height,
151 DRM_FORMAT_XRGB8888,
152 LOCAL_I915_FORMAT_MOD_X_TILED,
153 &fb[1]);
154
155 /* Bind both fb to the display (such that they are ready for future
156 * flips without stalling for the bind) leaving fb[0] as bound.
157 */
158 for (int i = 0; warmup[i] != -1; i++) {
159 struct drm_event_vblank ev;
160
161 do_or_die(drmModePageFlip(dpy->drm_fd,
162 dpy->pipes[pipe].crtc_id,
163 fb[warmup[i]].fb_id,
164 DRM_MODE_PAGE_FLIP_EVENT,
165 &fb[warmup[i]]));
166 igt_assert(read(dpy->drm_fd, &ev, sizeof(ev)) == sizeof(ev));
167 }
168
169 /* Make the frontbuffer busy and try to flip to itself */
170 flip_to_fb(dpy, pipe, output, &fb[0], ring, "fb[0]", modeset);
171
172 /* Repeat for flip to second buffer */
173 flip_to_fb(dpy, pipe, output, &fb[1], ring, "fb[1]", modeset);
174
175 do_cleanup_display(dpy);
176 igt_remove_fb(dpy->drm_fd, &fb[1]);
177 igt_remove_fb(dpy->drm_fd, &fb[0]);
178 }
179
test_atomic_commit_hang(igt_display_t * dpy,igt_plane_t * primary,struct igt_fb * busy_fb,unsigned ring)180 static void test_atomic_commit_hang(igt_display_t *dpy, igt_plane_t *primary,
181 struct igt_fb *busy_fb, unsigned ring)
182 {
183 igt_spin_t *t = igt_spin_new(dpy->drm_fd,
184 .engine = ring,
185 .dependency = busy_fb->gem_handle);
186 struct pollfd pfd = { .fd = dpy->drm_fd, .events = POLLIN };
187 unsigned flags = 0;
188 struct drm_event_vblank ev;
189
190 flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
191 flags |= DRM_MODE_ATOMIC_NONBLOCK;
192 flags |= DRM_MODE_PAGE_FLIP_EVENT;
193
194 igt_display_commit_atomic(dpy, flags, NULL);
195
196 igt_fork(child, 1) {
197 /*
198 * bit of a hack, just set atomic commit to NULL fb to make sure
199 * that we don't wait for the new update to complete.
200 */
201 igt_plane_set_fb(primary, NULL);
202 igt_display_commit_atomic(dpy, 0, NULL);
203
204 igt_assert_f(poll(&pfd, 1, 1) > 0,
205 "nonblocking update completed whilst fb[%d] was still busy [%d]\n",
206 busy_fb->fb_id, gem_bo_busy(dpy->drm_fd, busy_fb->gem_handle));
207 }
208
209 igt_waitchildren();
210
211 igt_assert(read(dpy->drm_fd, &ev, sizeof(ev)) == sizeof(ev));
212
213 igt_spin_end(t);
214 }
215
test_hang(igt_display_t * dpy,unsigned ring,enum pipe pipe,bool modeset,bool hang_newfb)216 static void test_hang(igt_display_t *dpy, unsigned ring,
217 enum pipe pipe, bool modeset, bool hang_newfb)
218 {
219 struct igt_fb fb[2];
220 igt_output_t *output;
221 igt_plane_t *primary;
222
223 output = set_fb_on_crtc(dpy, pipe, &fb[0]);
224 igt_display_commit2(dpy, COMMIT_ATOMIC);
225 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
226
227 igt_create_pattern_fb(dpy->drm_fd,
228 fb[0].width, fb[0].height,
229 DRM_FORMAT_XRGB8888,
230 LOCAL_I915_FORMAT_MOD_X_TILED,
231 &fb[1]);
232
233 if (modeset) {
234 /* Test modeset disable with hang */
235 igt_output_set_pipe(output, PIPE_NONE);
236 igt_plane_set_fb(primary, &fb[1]);
237 test_atomic_commit_hang(dpy, primary, &fb[hang_newfb], ring);
238
239 /* Test modeset enable with hang */
240 igt_plane_set_fb(primary, &fb[0]);
241 igt_output_set_pipe(output, pipe);
242 test_atomic_commit_hang(dpy, primary, &fb[!hang_newfb], ring);
243 } else {
244 /*
245 * Test what happens with a single hanging pageflip.
246 * This always completes early, because we have some
247 * timeouts taking care of it.
248 */
249 igt_plane_set_fb(primary, &fb[1]);
250 test_atomic_commit_hang(dpy, primary, &fb[hang_newfb], ring);
251 }
252
253 do_cleanup_display(dpy);
254 igt_remove_fb(dpy->drm_fd, &fb[1]);
255 igt_remove_fb(dpy->drm_fd, &fb[0]);
256 }
257
test_pageflip_modeset_hang(igt_display_t * dpy,unsigned ring,enum pipe pipe)258 static void test_pageflip_modeset_hang(igt_display_t *dpy,
259 unsigned ring, enum pipe pipe)
260 {
261 struct igt_fb fb;
262 struct drm_event_vblank ev;
263 igt_output_t *output;
264 igt_plane_t *primary;
265 igt_spin_t *t;
266
267 output = set_fb_on_crtc(dpy, pipe, &fb);
268 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
269
270 igt_display_commit2(dpy, dpy->is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY);
271
272 t = igt_spin_new(dpy->drm_fd,
273 .engine = ring,
274 .dependency = fb.gem_handle);
275
276 do_or_die(drmModePageFlip(dpy->drm_fd, dpy->pipes[pipe].crtc_id, fb.fb_id, DRM_MODE_PAGE_FLIP_EVENT, &fb));
277
278 /* Kill crtc with hung fb */
279 igt_plane_set_fb(primary, NULL);
280 igt_output_set_pipe(output, PIPE_NONE);
281 igt_display_commit2(dpy, dpy->is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY);
282
283 igt_assert(read(dpy->drm_fd, &ev, sizeof(ev)) == sizeof(ev));
284
285 igt_spin_end(t);
286
287 igt_remove_fb(dpy->drm_fd, &fb);
288 }
289
290 igt_main
291 {
292 igt_display_t display = { .drm_fd = -1, .n_pipes = IGT_MAX_PIPES };
293 /* we only test on render */
294 const struct intel_execution_engine *e = &intel_execution_engines[1];
295 enum pipe n;
296
297 igt_skip_on_simulation();
298
299 igt_fixture {
300 int fd = drm_open_driver_master(DRIVER_INTEL);
301
302 igt_require_gem(fd);
303 gem_require_mmap_wc(fd);
304
305 kmstest_set_vt_graphics_mode();
306 igt_display_require(&display, fd);
307 }
308
309 /* XXX Extend to cover atomic rendering tests to all planes + legacy */
310
for_each_pipe_static(n)311 for_each_pipe_static(n) igt_subtest_group {
312 igt_hang_t hang;
313
314 errno = 0;
315
316 igt_fixture {
317 igt_display_require_output_on_pipe(&display, n);
318 }
319
320 igt_subtest_f("basic-flip-%s",
321 kmstest_pipe_name(n)) {
322 igt_require(gem_has_ring(display.drm_fd,
323 e->exec_id | e->flags));
324
325 test_flip(&display, e->exec_id | e->flags, n, false);
326 }
327 igt_subtest_f("basic-modeset-%s",
328 kmstest_pipe_name(n)) {
329 igt_require(gem_has_ring(display.drm_fd,
330 e->exec_id | e->flags));
331
332 test_flip(&display, e->exec_id | e->flags, n, true);
333 }
334
335 igt_fixture {
336 igt_require(gem_has_ring(display.drm_fd,
337 e->exec_id | e->flags));
338
339 hang = igt_allow_hang(display.drm_fd, 0, 0);
340 }
341
342 igt_subtest_f("extended-pageflip-modeset-hang-oldfb-%s-%s",
343 e->name, kmstest_pipe_name(n)) {
344 igt_require(gem_has_ring(display.drm_fd,
345 e->exec_id | e->flags));
346
347 test_pageflip_modeset_hang(&display, e->exec_id | e->flags, n);
348 }
349
350 igt_fixture
351 igt_require(display.is_atomic);
352
353 igt_subtest_f("extended-pageflip-hang-oldfb-%s-%s",
354 e->name, kmstest_pipe_name(n))
355 test_hang(&display, e->exec_id | e->flags, n, false, false);
356
357 igt_subtest_f("extended-pageflip-hang-newfb-%s-%s",
358 e->name, kmstest_pipe_name(n))
359 test_hang(&display, e->exec_id | e->flags, n, false, true);
360
361 igt_subtest_f("extended-modeset-hang-oldfb-%s-%s",
362 e->name, kmstest_pipe_name(n))
363 test_hang(&display, e->exec_id | e->flags, n, true, false);
364
365 igt_subtest_f("extended-modeset-hang-newfb-%s-%s",
366 e->name, kmstest_pipe_name(n))
367 test_hang(&display, e->exec_id | e->flags, n, true, true);
368
369 igt_subtest_f("extended-modeset-hang-oldfb-with-reset-%s-%s",
370 e->name, kmstest_pipe_name(n)) {
371 igt_set_module_param_int("force_reset_modeset_test", 1);
372
373 test_hang(&display, e->exec_id | e->flags, n, true, false);
374
375 igt_set_module_param_int("force_reset_modeset_test", 0);
376 }
377
378 igt_subtest_f("extended-modeset-hang-newfb-with-reset-%s-%s",
379 e->name, kmstest_pipe_name(n)) {
380 igt_set_module_param_int("force_reset_modeset_test", 1);
381
382 test_hang(&display, e->exec_id | e->flags, n, true, true);
383
384 igt_set_module_param_int("force_reset_modeset_test", 0);
385 }
386
387 igt_fixture {
388 igt_disallow_hang(display.drm_fd, hang);
389 }
390 }
391
392 igt_fixture {
393 igt_display_fini(&display);
394 }
395 }
396