xref: /aosp_15_r20/external/igt-gpu-tools/tests/kms_atomic.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
1 /*
2  * Copyright © 2015 Intel Corporation
3  * Copyright © 2014-2015 Collabora, Ltd.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  *
24  * Authors:
25  *    Micah Fedke <[email protected]>
26  *    Daniel Stone <[email protected]>
27  *    Pekka Paalanen <[email protected]>
28  */
29 
30 /*
31  * Testcase: testing atomic modesetting API
32  */
33 
34 #include <unistd.h>
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <stdint.h>
38 #include <string.h>
39 #include <errno.h>
40 #include <xf86drmMode.h>
41 #include <cairo.h>
42 #include "drm.h"
43 #include "ioctl_wrappers.h"
44 #include "drmtest.h"
45 #include "igt.h"
46 #include "igt_aux.h"
47 #include "sw_sync.h"
48 
49 #ifndef DRM_CAP_CURSOR_WIDTH
50 #define DRM_CAP_CURSOR_WIDTH 0x8
51 #endif
52 
53 #ifndef DRM_CAP_CURSOR_HEIGHT
54 #define DRM_CAP_CURSOR_HEIGHT 0x9
55 #endif
56 
57 IGT_TEST_DESCRIPTION("Test atomic modesetting API");
58 
59 enum kms_atomic_check_relax {
60 	ATOMIC_RELAX_NONE = 0,
61 	CRTC_RELAX_MODE = (1 << 0),
62 	PLANE_RELAX_FB = (1 << 1)
63 };
64 
plane_filter(enum igt_atomic_plane_properties prop)65 static bool plane_filter(enum igt_atomic_plane_properties prop)
66 {
67 	if ((1 << prop) & IGT_PLANE_COORD_CHANGED_MASK)
68 		return false;
69 
70 	if (prop == IGT_PLANE_CRTC_ID || prop == IGT_PLANE_FB_ID)
71 		return false;
72 
73 	if (prop == IGT_PLANE_IN_FENCE_FD)
74 		return false;
75 
76 	/* Don't care about other properties */
77 	return true;
78 }
79 
plane_get_current_state(igt_plane_t * plane,uint64_t * values)80 static void plane_get_current_state(igt_plane_t *plane, uint64_t *values)
81 {
82 	int i;
83 
84 	for (i = 0; i < IGT_NUM_PLANE_PROPS; i++) {
85 		if (plane_filter(i)) {
86 			values[i] = 0;
87 			continue;
88 		}
89 
90 		values[i] = igt_plane_get_prop(plane, i);
91 	}
92 }
93 
plane_check_current_state(igt_plane_t * plane,const uint64_t * values,enum kms_atomic_check_relax relax)94 static void plane_check_current_state(igt_plane_t *plane, const uint64_t *values,
95 				      enum kms_atomic_check_relax relax)
96 {
97 	drmModePlanePtr legacy;
98 	uint64_t current_values[IGT_NUM_PLANE_PROPS];
99 	int i;
100 
101 	legacy = drmModeGetPlane(plane->pipe->display->drm_fd, plane->drm_plane->plane_id);
102 	igt_assert(legacy);
103 
104 	igt_assert_eq_u32(legacy->crtc_id, values[IGT_PLANE_CRTC_ID]);
105 
106 	if (!(relax & PLANE_RELAX_FB))
107 		igt_assert_eq_u32(legacy->fb_id, values[IGT_PLANE_FB_ID]);
108 
109 	plane_get_current_state(plane, current_values);
110 
111 	/* Legacy cursor ioctls create their own, unknowable, internal
112 	 * framebuffer which we can't reason about. */
113 	if (relax & PLANE_RELAX_FB)
114 		current_values[IGT_PLANE_FB_ID] = values[IGT_PLANE_FB_ID];
115 
116 	for (i = 0; i < IGT_NUM_PLANE_PROPS; i++)
117 		if (!plane_filter(i))
118 			igt_assert_eq_u64(current_values[i], values[i]);
119 
120 	drmModeFreePlane(legacy);
121 }
122 
plane_commit(igt_plane_t * plane,enum igt_commit_style s,enum kms_atomic_check_relax relax)123 static void plane_commit(igt_plane_t *plane, enum igt_commit_style s,
124                                 enum kms_atomic_check_relax relax)
125 {
126 	igt_display_commit2(plane->pipe->display, s);
127 	plane_check_current_state(plane, plane->values, relax);
128 }
129 
plane_commit_atomic_err(igt_plane_t * plane,enum kms_atomic_check_relax relax,int err)130 static void plane_commit_atomic_err(igt_plane_t *plane,
131 				    enum kms_atomic_check_relax relax,
132 				    int err)
133 {
134 	uint64_t current_values[IGT_NUM_PLANE_PROPS];
135 
136 	plane_get_current_state(plane, current_values);
137 
138 	igt_assert_eq(-err, igt_display_try_commit2(plane->pipe->display, COMMIT_ATOMIC));
139 
140 	plane_check_current_state(plane, current_values, relax);
141 }
142 
crtc_filter(enum igt_atomic_crtc_properties prop)143 static bool crtc_filter(enum igt_atomic_crtc_properties prop)
144 {
145 	if (prop == IGT_CRTC_MODE_ID || prop == IGT_CRTC_ACTIVE)
146 		return false;
147 
148 	return true;
149 }
150 
crtc_get_current_state(igt_pipe_t * pipe,uint64_t * values)151 static void crtc_get_current_state(igt_pipe_t *pipe, uint64_t *values)
152 {
153 	int i;
154 
155 	for (i = 0; i < IGT_NUM_CRTC_PROPS; i++) {
156 		if (crtc_filter(i)) {
157 			values[i] = 0;
158 			continue;
159 		}
160 
161 		values[i] = igt_pipe_obj_get_prop(pipe, i);
162 	}
163 }
164 
crtc_check_current_state(igt_pipe_t * pipe,const uint64_t * pipe_values,const uint64_t * primary_values,enum kms_atomic_check_relax relax)165 static void crtc_check_current_state(igt_pipe_t *pipe,
166 				     const uint64_t *pipe_values,
167 				     const uint64_t *primary_values,
168 				     enum kms_atomic_check_relax relax)
169 {
170 	uint64_t current_pipe_values[IGT_NUM_CRTC_PROPS];
171 	drmModeCrtcPtr legacy;
172 	drmModePropertyBlobRes *mode_prop = NULL;
173 	struct drm_mode_modeinfo *mode = NULL;
174 
175 	if (pipe_values[IGT_CRTC_MODE_ID]) {
176 		mode_prop = drmModeGetPropertyBlob(pipe->display->drm_fd,
177 						   pipe_values[IGT_CRTC_MODE_ID]);
178 
179 		igt_assert(mode_prop);
180 
181 		igt_assert_eq(mode_prop->length,
182 		              sizeof(struct drm_mode_modeinfo));
183 		mode = mode_prop->data;
184 	}
185 
186 	legacy = drmModeGetCrtc(pipe->display->drm_fd, pipe->crtc_id);
187 	igt_assert(legacy);
188 
189 	igt_assert_eq_u32(legacy->crtc_id, pipe->crtc_id);
190 	igt_assert_eq_u32(legacy->x, primary_values[IGT_PLANE_SRC_X] >> 16);
191 	igt_assert_eq_u32(legacy->y, primary_values[IGT_PLANE_SRC_Y] >> 16);
192 
193 	igt_assert_eq_u32(legacy->buffer_id, primary_values[IGT_PLANE_FB_ID]);
194 
195 	if (legacy->mode_valid) {
196 		igt_assert(mode_prop);
197 
198 		do_or_die(memcmp(&legacy->mode, mode, sizeof(*mode)));
199 
200 		igt_assert_eq(legacy->width, legacy->mode.hdisplay);
201 		igt_assert_eq(legacy->height, legacy->mode.vdisplay);
202 
203 		igt_assert_neq(pipe_values[IGT_CRTC_MODE_ID], 0);
204 	} else {
205 		igt_assert(!mode_prop);
206 	}
207 
208 	crtc_get_current_state(pipe, current_pipe_values);
209 
210 	/* Optionally relax the check for MODE_ID: using the legacy SetCrtc
211 	 * API can potentially change MODE_ID even if the mode itself remains
212 	 * unchanged. */
213 	if (relax & CRTC_RELAX_MODE && mode && current_pipe_values[IGT_CRTC_MODE_ID] &&
214 	    current_pipe_values[IGT_CRTC_MODE_ID] != pipe_values[IGT_CRTC_MODE_ID]) {
215 		drmModePropertyBlobRes *cur_prop =
216 			drmModeGetPropertyBlob(pipe->display->drm_fd,
217 					       current_pipe_values[IGT_CRTC_MODE_ID]);
218 
219 		igt_assert(cur_prop);
220 		igt_assert_eq(cur_prop->length, sizeof(struct drm_mode_modeinfo));
221 
222 		if (!memcmp(cur_prop->data, mode, sizeof(*mode)))
223 			current_pipe_values[IGT_CRTC_MODE_ID] = pipe_values[IGT_CRTC_MODE_ID];
224 
225 		drmModeFreePropertyBlob(cur_prop);
226 	}
227 
228 	do_or_die(memcmp(pipe_values, current_pipe_values, sizeof(current_pipe_values)));
229 
230 	drmModeFreeCrtc(legacy);
231 	drmModeFreePropertyBlob(mode_prop);
232 }
233 
crtc_commit(igt_pipe_t * pipe,igt_plane_t * plane,enum igt_commit_style s,enum kms_atomic_check_relax relax)234 static void crtc_commit(igt_pipe_t *pipe, igt_plane_t *plane,
235 			enum igt_commit_style s,
236 			enum kms_atomic_check_relax relax)
237 {
238 	igt_display_commit2(pipe->display, s);
239 
240 	crtc_check_current_state(pipe, pipe->values, plane->values, relax);
241 	plane_check_current_state(plane, plane->values, relax);
242 }
243 
crtc_commit_atomic_flags_err(igt_pipe_t * pipe,igt_plane_t * plane,unsigned flags,enum kms_atomic_check_relax relax,int err)244 static void crtc_commit_atomic_flags_err(igt_pipe_t *pipe, igt_plane_t *plane,
245 					 unsigned flags,
246 					 enum kms_atomic_check_relax relax,
247 					 int err)
248 {
249 	uint64_t current_pipe_values[IGT_NUM_CRTC_PROPS];
250 	uint64_t current_plane_values[IGT_NUM_PLANE_PROPS];
251 
252 	crtc_get_current_state(pipe, current_pipe_values);
253 	plane_get_current_state(plane, current_plane_values);
254 
255 	igt_assert_eq(-err, igt_display_try_commit_atomic(pipe->display, flags, NULL));
256 
257 	crtc_check_current_state(pipe, current_pipe_values, current_plane_values, relax);
258 	plane_check_current_state(plane, current_plane_values, relax);
259 }
260 
261 #define crtc_commit_atomic_err(pipe, plane, relax, err) \
262 	crtc_commit_atomic_flags_err(pipe, plane, DRM_MODE_ATOMIC_ALLOW_MODESET, relax, err)
263 
plane_get_igt_format(igt_plane_t * plane)264 static uint32_t plane_get_igt_format(igt_plane_t *plane)
265 {
266 	drmModePlanePtr plane_kms;
267 	int i;
268 
269 	plane_kms = plane->drm_plane;
270 
271 	for (i = 0; i < plane_kms->count_formats; i++) {
272 		if (igt_fb_supported_format(plane_kms->formats[i]))
273 			return plane_kms->formats[i];
274 	}
275 
276 	return 0;
277 }
278 
279 static void
plane_primary_overlay_zpos(igt_pipe_t * pipe,igt_output_t * output,igt_plane_t * primary,igt_plane_t * overlay,uint32_t format_primary,uint32_t format_overlay)280 plane_primary_overlay_zpos(igt_pipe_t *pipe, igt_output_t *output,
281 			   igt_plane_t *primary, igt_plane_t *overlay,
282 			   uint32_t format_primary, uint32_t format_overlay)
283 {
284 	struct igt_fb fb_primary, fb_overlay;
285 	drmModeModeInfo *mode = igt_output_get_mode(output);
286 	cairo_t *cr;
287 
288 	/* for primary */
289 	uint32_t w = mode->hdisplay;
290 	uint32_t h = mode->vdisplay;
291 
292 	/* for overlay */
293 	uint32_t w_overlay = mode->hdisplay / 2;
294 	uint32_t h_overlay = mode->vdisplay / 2;
295 
296 	igt_create_color_pattern_fb(pipe->display->drm_fd,
297 				    w, h, format_primary, I915_TILING_NONE,
298 				    0.2, 0.2, 0.2, &fb_primary);
299 
300 	igt_create_color_pattern_fb(pipe->display->drm_fd,
301 				    w_overlay, h_overlay,
302 				    format_overlay, I915_TILING_NONE,
303 				    0.2, 0.2, 0.2, &fb_overlay);
304 
305 #if defined(USE_CAIRO_PIXMAN)
306 	/* Draw a hole in the overlay */
307 	cr = igt_get_cairo_ctx(pipe->display->drm_fd, &fb_overlay);
308 	cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
309 	igt_paint_color_alpha(cr, w_overlay / 4, h_overlay / 4,
310 			      w_overlay / 2, h_overlay / 2,
311 			      0.0, 0.0, 0.0, 0.0);
312 	cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
313 	igt_put_cairo_ctx(pipe->display->drm_fd, &fb_overlay, cr);
314 #endif
315 
316 	igt_plane_set_fb(primary, &fb_primary);
317 	igt_plane_set_fb(overlay, &fb_overlay);
318 
319 	igt_plane_set_position(overlay, w_overlay / 2, h_overlay / 2);
320 
321 	igt_plane_set_prop_value(primary, IGT_PLANE_ZPOS, 0);
322 	igt_plane_set_prop_value(overlay, IGT_PLANE_ZPOS, 1);
323 
324 	igt_info("Committing with overlay on top, it has a hole "\
325 		  "through which the primary should be seen\n");
326 	plane_commit(primary, COMMIT_ATOMIC, ATOMIC_RELAX_NONE);
327 
328 	igt_assert_eq_u64(igt_plane_get_prop(primary, IGT_PLANE_ZPOS), 0);
329 	igt_assert_eq_u64(igt_plane_get_prop(overlay, IGT_PLANE_ZPOS), 1);
330 
331 	igt_plane_set_prop_value(primary, IGT_PLANE_ZPOS, 1);
332 	igt_plane_set_prop_value(overlay, IGT_PLANE_ZPOS, 0);
333 
334 	igt_info("Committing with primary on top, only the primary "\
335 		 "should be visible\n");
336 	plane_commit(primary, COMMIT_ATOMIC, ATOMIC_RELAX_NONE);
337 
338 	igt_assert_eq_u64(igt_plane_get_prop(primary, IGT_PLANE_ZPOS), 1);
339 	igt_assert_eq_u64(igt_plane_get_prop(overlay, IGT_PLANE_ZPOS), 0);
340 
341 	/* Draw a hole in the primary exactly on top of the overlay plane */
342 #if defined(USE_CAIRO_PIXMAN)
343 	cr = igt_get_cairo_ctx(pipe->display->drm_fd, &fb_primary);
344 	cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
345 	igt_paint_color_alpha(cr, w_overlay / 2, h_overlay / 2,
346 			      w_overlay, h_overlay,
347 			      0.0, 0.0, 0.0, 0.5);
348 	cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
349 	igt_put_cairo_ctx(pipe->display->drm_fd, &fb_primary, cr);
350 #endif
351 
352 	igt_info("Committing with a hole in the primary through "\
353 		  "which the underlay should be seen\n");
354 	plane_commit(primary, COMMIT_ATOMIC, ATOMIC_RELAX_NONE);
355 
356 	/* reset it back to initial state */
357 	igt_plane_set_prop_value(primary, IGT_PLANE_ZPOS, 0);
358 	igt_plane_set_prop_value(overlay, IGT_PLANE_ZPOS, 1);
359 	plane_commit(primary, COMMIT_ATOMIC, ATOMIC_RELAX_NONE);
360 
361 	igt_assert_eq_u64(igt_plane_get_prop(primary, IGT_PLANE_ZPOS), 0);
362 	igt_assert_eq_u64(igt_plane_get_prop(overlay, IGT_PLANE_ZPOS), 1);
363 }
364 
plane_overlay(igt_pipe_t * pipe,igt_output_t * output,igt_plane_t * plane)365 static void plane_overlay(igt_pipe_t *pipe, igt_output_t *output, igt_plane_t *plane)
366 {
367 	drmModeModeInfo *mode = igt_output_get_mode(output);
368 	uint32_t format = plane_get_igt_format(plane);
369 	struct igt_fb fb;
370 	uint32_t w = mode->hdisplay / 2;
371 	uint32_t h = mode->vdisplay / 2;
372 
373 	igt_require(format != 0);
374 
375 	igt_create_pattern_fb(pipe->display->drm_fd, w, h,
376 			      format, I915_TILING_NONE, &fb);
377 
378 	igt_plane_set_fb(plane, &fb);
379 	igt_plane_set_position(plane, w/2, h/2);
380 
381 	/* Enable the overlay plane using the atomic API, and double-check
382 	 * state is what we think it should be. */
383 	plane_commit(plane, COMMIT_ATOMIC, ATOMIC_RELAX_NONE);
384 
385 	/* Disable the plane and check the state matches the old. */
386 	igt_plane_set_fb(plane, NULL);
387 	igt_plane_set_position(plane, 0, 0);
388 	plane_commit(plane, COMMIT_ATOMIC, ATOMIC_RELAX_NONE);
389 
390 	/* Re-enable the plane through the legacy plane API, and verify through
391 	 * atomic. */
392 	igt_plane_set_fb(plane, &fb);
393 	igt_plane_set_position(plane, w/2, h/2);
394 	plane_commit(plane, COMMIT_LEGACY, ATOMIC_RELAX_NONE);
395 
396 	/* Restore the plane to its original settings through the legacy plane
397 	 * API, and verify through atomic. */
398 	igt_plane_set_fb(plane, NULL);
399 	igt_plane_set_position(plane, 0, 0);
400 	plane_commit(plane, COMMIT_LEGACY, ATOMIC_RELAX_NONE);
401 
402 	igt_remove_fb(pipe->display->drm_fd, &fb);
403 }
404 
plane_primary(igt_pipe_t * pipe,igt_plane_t * plane,struct igt_fb * fb)405 static void plane_primary(igt_pipe_t *pipe, igt_plane_t *plane, struct igt_fb *fb)
406 {
407 	struct igt_fb fb2;
408 
409 	igt_create_color_pattern_fb(pipe->display->drm_fd,
410 				    fb->width, fb->height,
411 				    fb->drm_format, I915_TILING_NONE,
412 				    0.2, 0.2, 0.2, &fb2);
413 
414 	/* Flip the primary plane using the atomic API, and double-check
415 	 * state is what we think it should be. */
416 	igt_plane_set_fb(plane, &fb2);
417 	crtc_commit(pipe, plane, COMMIT_ATOMIC, ATOMIC_RELAX_NONE);
418 
419 	/* Restore the primary plane and check the state matches the old. */
420 	igt_plane_set_fb(plane, fb);
421 	crtc_commit(pipe, plane, COMMIT_ATOMIC, ATOMIC_RELAX_NONE);
422 
423 	/* Set the plane through the legacy CRTC/primary-plane API, and
424 	 * verify through atomic. */
425 	igt_plane_set_fb(plane, &fb2);
426 	crtc_commit(pipe, plane, COMMIT_LEGACY, CRTC_RELAX_MODE);
427 
428 	/* Restore the plane to its original settings through the legacy CRTC
429 	 * API, and verify through atomic. */
430 	igt_plane_set_fb(plane, fb);
431 	crtc_commit(pipe, plane, COMMIT_LEGACY, CRTC_RELAX_MODE);
432 
433 	/* Set the plane through the universal setplane API, and
434 	 * verify through atomic. */
435 	igt_plane_set_fb(plane, &fb2);
436 	plane_commit(plane, COMMIT_UNIVERSAL, ATOMIC_RELAX_NONE);
437 }
438 
439 /* test to ensure that DRM_MODE_ATOMIC_TEST_ONLY really only touches the
440  * free-standing state objects and nothing else.
441  */
test_only(igt_pipe_t * pipe_obj,igt_plane_t * primary,igt_output_t * output)442 static void test_only(igt_pipe_t *pipe_obj,
443 		      igt_plane_t *primary,
444 		      igt_output_t *output)
445 {
446 	drmModeModeInfo *mode = igt_output_get_mode(output);
447 	uint32_t format = plane_get_igt_format(primary);
448 	struct igt_fb fb;
449 	uint64_t old_plane_values[IGT_NUM_PLANE_PROPS], old_crtc_values[IGT_NUM_CRTC_PROPS];
450 
451 	igt_require(format != 0);
452 
453 	plane_get_current_state(primary, old_plane_values);
454 	crtc_get_current_state(pipe_obj, old_crtc_values);
455 
456 	igt_assert(!old_crtc_values[IGT_CRTC_MODE_ID]);
457 
458 	igt_create_pattern_fb(pipe_obj->display->drm_fd,
459 			     mode->hdisplay, mode->vdisplay,
460 			     format, I915_TILING_NONE, &fb);
461 	igt_plane_set_fb(primary, &fb);
462 	igt_output_set_pipe(output, pipe_obj->pipe);
463 
464 	igt_display_commit_atomic(pipe_obj->display, DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
465 
466 	/* check the state, should still be old state */
467 	crtc_check_current_state(pipe_obj, old_crtc_values, old_plane_values, ATOMIC_RELAX_NONE);
468 	plane_check_current_state(primary, old_plane_values, ATOMIC_RELAX_NONE);
469 
470 	/*
471 	 * Enable the plane through the legacy CRTC/primary-plane API, and
472 	 * verify through atomic.
473 	 */
474 	crtc_commit(pipe_obj, primary, COMMIT_LEGACY, CRTC_RELAX_MODE);
475 
476 	/* Same for disable.. */
477 	plane_get_current_state(primary, old_plane_values);
478 	crtc_get_current_state(pipe_obj, old_crtc_values);
479 
480 	igt_plane_set_fb(primary, NULL);
481 	igt_output_set_pipe(output, PIPE_NONE);
482 
483 	igt_display_commit_atomic(pipe_obj->display, DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
484 
485 	/* for extra stress, go through dpms off/on cycle */
486 	kmstest_set_connector_dpms(output->display->drm_fd, output->config.connector, DRM_MODE_DPMS_OFF);
487 	kmstest_set_connector_dpms(output->display->drm_fd, output->config.connector, DRM_MODE_DPMS_ON);
488 
489 	/* check the state, should still be old state */
490 	crtc_check_current_state(pipe_obj, old_crtc_values, old_plane_values, ATOMIC_RELAX_NONE);
491 	plane_check_current_state(primary, old_plane_values, ATOMIC_RELAX_NONE);
492 
493 	/* And disable the pipe and remove fb, test complete */
494 	crtc_commit(pipe_obj, primary, COMMIT_ATOMIC, ATOMIC_RELAX_NONE);
495 	igt_remove_fb(pipe_obj->display->drm_fd, &fb);
496 }
497 
plane_cursor(igt_pipe_t * pipe_obj,igt_output_t * output,igt_plane_t * cursor)498 static void plane_cursor(igt_pipe_t *pipe_obj,
499 			 igt_output_t *output,
500 			 igt_plane_t *cursor)
501 {
502 	drmModeModeInfo *mode = igt_output_get_mode(output);
503 	struct igt_fb fb;
504 	uint64_t width, height;
505 	int x = mode->hdisplay / 2;
506 	int y = mode->vdisplay / 2;
507 
508 	/* Any kernel new enough for atomic, also has the cursor size caps. */
509 	do_or_die(drmGetCap(pipe_obj->display->drm_fd,
510 	                    DRM_CAP_CURSOR_WIDTH, &width));
511 	do_or_die(drmGetCap(pipe_obj->display->drm_fd,
512 	                    DRM_CAP_CURSOR_HEIGHT, &height));
513 
514 	igt_create_color_fb(pipe_obj->display->drm_fd,
515 			    width, height, DRM_FORMAT_ARGB8888,
516 			    LOCAL_DRM_FORMAT_MOD_NONE,
517 			    0.0, 0.0, 0.0, &fb);
518 
519 	/* Flip the cursor plane using the atomic API, and double-check
520 	 * state is what we think it should be. */
521 	igt_plane_set_fb(cursor, &fb);
522 	igt_plane_set_position(cursor, x, y);
523 	plane_commit(cursor, COMMIT_ATOMIC, ATOMIC_RELAX_NONE);
524 
525 	/* Restore the cursor plane and check the state matches the old. */
526 	igt_plane_set_fb(cursor, NULL);
527 	igt_plane_set_position(cursor, 0, 0);
528 	plane_commit(cursor, COMMIT_ATOMIC, ATOMIC_RELAX_NONE);
529 
530 	/* Re-enable the plane through the legacy cursor API, and verify
531 	 * through atomic. */
532 	igt_plane_set_fb(cursor, &fb);
533 	igt_plane_set_position(cursor, x, y);
534 	plane_commit(cursor, COMMIT_LEGACY, PLANE_RELAX_FB);
535 
536 	/* Wiggle. */
537 	igt_plane_set_position(cursor, x - 16, y - 16);
538 	plane_commit(cursor, COMMIT_LEGACY, PLANE_RELAX_FB);
539 
540 	/* Restore the plane to its original settings through the legacy cursor
541 	 * API, and verify through atomic. */
542 	igt_plane_set_fb(cursor, NULL);
543 	igt_plane_set_position(cursor, 0, 0);
544 	plane_commit(cursor, COMMIT_LEGACY, ATOMIC_RELAX_NONE);
545 }
546 
plane_invalid_params(igt_pipe_t * pipe,igt_output_t * output,igt_plane_t * plane,struct igt_fb * fb)547 static void plane_invalid_params(igt_pipe_t *pipe,
548 				 igt_output_t *output,
549 				 igt_plane_t *plane,
550 				 struct igt_fb *fb)
551 {
552 	struct igt_fb fb2;
553 
554 	/* Pass a series of invalid object IDs for the FB ID. */
555 	igt_plane_set_prop_value(plane, IGT_PLANE_FB_ID, plane->drm_plane->plane_id);
556 	plane_commit_atomic_err(plane, ATOMIC_RELAX_NONE, EINVAL);
557 
558 	igt_plane_set_prop_value(plane, IGT_PLANE_FB_ID, pipe->crtc_id);
559 	plane_commit_atomic_err(plane, ATOMIC_RELAX_NONE, EINVAL);
560 
561 	igt_plane_set_prop_value(plane, IGT_PLANE_FB_ID, output->id);
562 	plane_commit_atomic_err(plane, ATOMIC_RELAX_NONE, EINVAL);
563 
564 	igt_plane_set_prop_value(plane, IGT_PLANE_FB_ID, pipe->values[IGT_CRTC_MODE_ID]);
565 	plane_commit_atomic_err(plane, ATOMIC_RELAX_NONE, EINVAL);
566 
567 	/* Valid, but invalid because CRTC_ID is set. */
568 	igt_plane_set_prop_value(plane, IGT_PLANE_FB_ID, 0);
569 	plane_commit_atomic_err(plane, ATOMIC_RELAX_NONE, EINVAL);
570 
571 	igt_plane_set_fb(plane, fb);
572 	plane_commit(plane, COMMIT_ATOMIC, ATOMIC_RELAX_NONE);
573 
574 	/* Pass a series of invalid object IDs for the CRTC ID. */
575 	igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_ID, plane->drm_plane->plane_id);
576 	plane_commit_atomic_err(plane, ATOMIC_RELAX_NONE, EINVAL);
577 
578 	igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_ID, fb->fb_id);
579 	plane_commit_atomic_err(plane, ATOMIC_RELAX_NONE, EINVAL);
580 
581 	igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_ID, output->id);
582 	plane_commit_atomic_err(plane, ATOMIC_RELAX_NONE, EINVAL);
583 
584 	igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_ID, pipe->values[IGT_CRTC_MODE_ID]);
585 	plane_commit_atomic_err(plane, ATOMIC_RELAX_NONE, EINVAL);
586 
587 	/* Valid, but invalid because FB_ID is set. */
588 	igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_ID, 0);
589 	plane_commit_atomic_err(plane, ATOMIC_RELAX_NONE, EINVAL);
590 
591 	igt_plane_set_fb(plane, fb);
592 	plane_commit(plane, COMMIT_ATOMIC, ATOMIC_RELAX_NONE);
593 
594 	/* Create a framebuffer too small for the plane configuration. */
595 	igt_create_pattern_fb(pipe->display->drm_fd,
596 			      fb->width - 1, fb->height - 1,
597 			      fb->drm_format, I915_TILING_NONE, &fb2);
598 
599 	igt_plane_set_prop_value(plane, IGT_PLANE_FB_ID, fb2.fb_id);
600 	plane_commit_atomic_err(plane, ATOMIC_RELAX_NONE, ENOSPC);
601 
602 	/* Restore the primary plane and check the state matches the old. */
603 	igt_plane_set_fb(plane, fb);
604 	plane_commit(plane, COMMIT_ATOMIC, ATOMIC_RELAX_NONE);
605 }
606 
plane_invalid_params_fence(igt_pipe_t * pipe,igt_output_t * output,igt_plane_t * plane)607 static void plane_invalid_params_fence(igt_pipe_t *pipe,
608 				       igt_output_t *output,
609 				       igt_plane_t *plane)
610 {
611 	int timeline, fence_fd;
612 
613 	igt_require_sw_sync();
614 
615 	timeline = sw_sync_timeline_create();
616 
617 	/* invalid fence fd */
618 	igt_plane_set_fence_fd(plane, pipe->display->drm_fd);
619 	plane_commit_atomic_err(plane, ATOMIC_RELAX_NONE, EINVAL);
620 
621 	/* Valid fence_fd but invalid CRTC */
622 	fence_fd = sw_sync_timeline_create_fence(timeline, 1);
623 
624 	igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_ID, ~0);
625 	igt_plane_set_fence_fd(plane, fence_fd);
626 	plane_commit_atomic_err(plane, ATOMIC_RELAX_NONE, EINVAL);
627 
628 	sw_sync_timeline_inc(timeline, 1);
629 	igt_plane_set_prop_value(plane, IGT_PLANE_CRTC_ID, pipe->crtc_id);
630 	plane_commit(plane, COMMIT_ATOMIC, ATOMIC_RELAX_NONE);
631 
632 	close(fence_fd);
633 	close(timeline);
634 }
635 
crtc_invalid_params(igt_pipe_t * pipe,igt_output_t * output,igt_plane_t * plane,struct igt_fb * fb)636 static void crtc_invalid_params(igt_pipe_t *pipe,
637 				igt_output_t *output,
638 				igt_plane_t *plane,
639 				struct igt_fb *fb)
640 {
641 	uint64_t old_mode_id = pipe->values[IGT_CRTC_MODE_ID];
642 	drmModeModeInfo *mode = igt_output_get_mode(output);
643 
644 	/* Pass a series of invalid object IDs for the mode ID. */
645 	igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_MODE_ID, plane->drm_plane->plane_id);
646 	crtc_commit_atomic_err(pipe, plane, ATOMIC_RELAX_NONE, EINVAL);
647 
648 	igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_MODE_ID, pipe->crtc_id);
649 	crtc_commit_atomic_err(pipe, plane, ATOMIC_RELAX_NONE, EINVAL);
650 
651 	igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_MODE_ID, output->id);
652 	crtc_commit_atomic_err(pipe, plane, ATOMIC_RELAX_NONE, EINVAL);
653 
654 	igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_MODE_ID, fb->fb_id);
655 	crtc_commit_atomic_err(pipe, plane, ATOMIC_RELAX_NONE, EINVAL);
656 
657 	/* Can we restore mode? */
658 	igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_MODE_ID, old_mode_id);
659 	crtc_commit_atomic_flags_err(pipe, plane, DRM_MODE_ATOMIC_TEST_ONLY, ATOMIC_RELAX_NONE, 0);
660 
661 	/*
662 	 * TEST_ONLY cannot be combined with DRM_MODE_PAGE_FLIP_EVENT,
663 	 * but DRM_MODE_PAGE_FLIP_EVENT will always generate EINVAL
664 	 * without valid crtc, so test it here.
665 	 */
666 	crtc_commit_atomic_flags_err(pipe, plane,
667 				     DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_PAGE_FLIP_EVENT,
668 				     ATOMIC_RELAX_NONE, EINVAL);
669 
670 	/* Create a blob which is the wrong size to be a valid mode. */
671 	igt_pipe_obj_replace_prop_blob(pipe, IGT_CRTC_MODE_ID, mode, sizeof(*mode) - 1);
672 	crtc_commit_atomic_err(pipe, plane, ATOMIC_RELAX_NONE, EINVAL);
673 
674 	igt_pipe_obj_replace_prop_blob(pipe, IGT_CRTC_MODE_ID, mode, sizeof(*mode) + 1);
675 	crtc_commit_atomic_err(pipe, plane, ATOMIC_RELAX_NONE, EINVAL);
676 
677 
678 	/* Restore the CRTC and check the state matches the old. */
679 	igt_pipe_obj_replace_prop_blob(pipe, IGT_CRTC_MODE_ID, mode, sizeof(*mode));
680 	crtc_commit(pipe, plane, COMMIT_ATOMIC, ATOMIC_RELAX_NONE);
681 }
682 
crtc_invalid_params_fence(igt_pipe_t * pipe,igt_output_t * output,igt_plane_t * plane,struct igt_fb * fb)683 static void crtc_invalid_params_fence(igt_pipe_t *pipe,
684 				      igt_output_t *output,
685 				      igt_plane_t *plane,
686 				      struct igt_fb *fb)
687 {
688 	int timeline, fence_fd;
689 	void *map;
690 	const ptrdiff_t page_size = sysconf(_SC_PAGE_SIZE);
691 
692 	uint64_t old_mode_id = pipe->values[IGT_CRTC_MODE_ID];
693 
694 	igt_require_sw_sync();
695 
696 	timeline = sw_sync_timeline_create();
697 
698 	/* invalid out_fence_ptr */
699 	map = mmap(NULL, page_size, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
700 	igt_assert(map != MAP_FAILED);
701 
702 	igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_OUT_FENCE_PTR, (ptrdiff_t)map);
703 	crtc_commit_atomic_err(pipe, plane, ATOMIC_RELAX_NONE, EFAULT);
704 	munmap(map, page_size);
705 
706 	/* invalid out_fence_ptr */
707 	map = mmap(NULL, page_size, PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
708 	igt_assert(map != MAP_FAILED);
709 
710 	igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_OUT_FENCE_PTR, (ptrdiff_t)map);
711 	crtc_commit_atomic_err(pipe, plane, ATOMIC_RELAX_NONE, EFAULT);
712 	munmap(map, page_size);
713 
714 	/* invalid out_fence_ptr */
715 	map = mmap(NULL, page_size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
716 	igt_assert(map != MAP_FAILED);
717 
718 	igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_OUT_FENCE_PTR, (ptrdiff_t)map);
719 	crtc_commit_atomic_err(pipe, plane, ATOMIC_RELAX_NONE, EFAULT);
720 	munmap(map, page_size);
721 
722 	/* valid in fence but not allowed prop on crtc */
723 	fence_fd = sw_sync_timeline_create_fence(timeline, 1);
724 	igt_plane_set_fence_fd(plane, fence_fd);
725 
726 	igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_ACTIVE, 0);
727 	igt_pipe_obj_clear_prop_changed(pipe, IGT_CRTC_OUT_FENCE_PTR);
728 
729 	crtc_commit_atomic_flags_err(pipe, plane, 0, ATOMIC_RELAX_NONE, EINVAL);
730 
731 	/* valid out fence ptr and flip event but not allowed prop on crtc */
732 	igt_pipe_request_out_fence(pipe);
733 	crtc_commit_atomic_flags_err(pipe, plane, DRM_MODE_PAGE_FLIP_EVENT,
734 				     ATOMIC_RELAX_NONE, EINVAL);
735 
736 	/* valid flip event but not allowed prop on crtc */
737 	igt_pipe_obj_clear_prop_changed(pipe, IGT_CRTC_OUT_FENCE_PTR);
738 	crtc_commit_atomic_flags_err(pipe, plane, DRM_MODE_PAGE_FLIP_EVENT,
739 				     ATOMIC_RELAX_NONE, EINVAL);
740 
741 	igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_ACTIVE, 1);
742 
743 	/* Configuration should be valid again */
744 	crtc_commit_atomic_flags_err(pipe, plane, DRM_MODE_ATOMIC_TEST_ONLY,
745 				     ATOMIC_RELAX_NONE, 0);
746 
747 	/* Set invalid prop */
748 	igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_MODE_ID, fb->fb_id);
749 
750 	/* valid out fence but invalid prop on crtc */
751 	igt_pipe_request_out_fence(pipe);
752 	crtc_commit_atomic_flags_err(pipe, plane, 0,
753 				     ATOMIC_RELAX_NONE, EINVAL);
754 
755 	/* valid out fence ptr and flip event but invalid prop on crtc */
756 	crtc_commit_atomic_flags_err(pipe, plane, DRM_MODE_PAGE_FLIP_EVENT,
757 				     ATOMIC_RELAX_NONE, EINVAL);
758 
759 	/* valid page flip event but invalid prop on crtc */
760 	crtc_commit_atomic_flags_err(pipe, plane, DRM_MODE_PAGE_FLIP_EVENT,
761 				     ATOMIC_RELAX_NONE, EINVAL);
762 
763 	/* successful TEST_ONLY with fences set */
764 	igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_MODE_ID, old_mode_id);
765 	crtc_commit_atomic_flags_err(pipe, plane, DRM_MODE_ATOMIC_TEST_ONLY,
766 				     ATOMIC_RELAX_NONE, 0);
767 	igt_assert(pipe->out_fence_fd == -1);
768 	close(fence_fd);
769 	close(timeline);
770 
771 	/* reset fences */
772 	igt_plane_set_fence_fd(plane, -1);
773 	igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_OUT_FENCE_PTR, 0);
774 	igt_pipe_obj_clear_prop_changed(pipe, IGT_CRTC_OUT_FENCE_PTR);
775 	crtc_commit(pipe, plane, COMMIT_ATOMIC, ATOMIC_RELAX_NONE);
776 
777 	/* out fence ptr but not page flip event */
778 	igt_pipe_request_out_fence(pipe);
779 	crtc_commit(pipe, plane, COMMIT_ATOMIC, ATOMIC_RELAX_NONE);
780 
781 	igt_assert(pipe->out_fence_fd != -1);
782 }
783 
784 /* Abuse the atomic ioctl directly in order to test various invalid conditions,
785  * which the libdrm wrapper won't allow us to create. */
atomic_invalid_params(igt_pipe_t * pipe,igt_plane_t * plane,igt_output_t * output,struct igt_fb * fb)786 static void atomic_invalid_params(igt_pipe_t *pipe,
787 				  igt_plane_t *plane,
788 				  igt_output_t *output,
789 				  struct igt_fb *fb)
790 {
791 	igt_display_t *display = pipe->display;
792 	struct drm_mode_atomic ioc;
793 	uint32_t obj_raw[16]; /* array of objects (sized by count_objs) */
794 	uint32_t num_props_raw[16]; /* array of num props per obj (ditto) */
795 	uint32_t props_raw[256]; /* array of props (sum of count_props) */
796 	uint64_t values_raw[256]; /* array of values for properties (ditto) */
797 	int i;
798 
799 	memset(&ioc, 0, sizeof(ioc));
800 
801 	/* An empty request should do nothing. */
802 	do_ioctl(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc);
803 
804 	for (i = 0; i < ARRAY_SIZE(obj_raw); i++)
805 		obj_raw[i] = 0;
806 	for (i = 0; i < ARRAY_SIZE(num_props_raw); i++)
807 		num_props_raw[i] = 0;
808 	for (i = 0; i < ARRAY_SIZE(props_raw); i++)
809 		props_raw[i] = 0;
810 	for (i = 0; i < ARRAY_SIZE(values_raw); i++)
811 		values_raw[i] = 0;
812 
813 	ioc.objs_ptr = (uintptr_t) obj_raw;
814 	ioc.count_props_ptr = (uintptr_t) num_props_raw;
815 	ioc.props_ptr = (uintptr_t) props_raw;
816 	ioc.prop_values_ptr = (uintptr_t) values_raw;
817 
818 	/* Valid pointers, but still should copy nothing. */
819 	do_ioctl(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc);
820 
821 	/* Valid noop, but with event set should fail. */
822 	ioc.flags = DRM_MODE_PAGE_FLIP_EVENT;
823 	do_ioctl_err(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc, EINVAL);
824 
825 	/* Nonsense flags. */
826 	ioc.flags = 0xdeadbeef;
827 	do_ioctl_err(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc, EINVAL);
828 
829 	ioc.flags = 0;
830 	/* Safety check that flags is reset properly. */
831 	do_ioctl(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc);
832 
833 	/* Reserved/MBZ. */
834 	ioc.reserved = 1;
835 	do_ioctl_err(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc, EINVAL);
836 	ioc.reserved = 0;
837 	do_ioctl(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc);
838 
839 	/* Zero is not a valid object ID. */
840 	ioc.count_objs = ARRAY_SIZE(obj_raw);
841 	do_ioctl_err(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc, ENOENT);
842 
843 	/* Invalid object type (not a thing we can set properties on). */
844 	ioc.count_objs = 1;
845 	obj_raw[0] = pipe->values[IGT_CRTC_MODE_ID];
846 	do_ioctl_err(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc, ENOENT);
847 	obj_raw[0] = fb->fb_id;
848 	do_ioctl_err(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc, ENOENT);
849 
850 	/* Filled object but with no properties; no-op. */
851 	for (i = 0; i < ARRAY_SIZE(obj_raw); i++)
852 		obj_raw[i] = pipe->crtc_id;
853 	do_ioctl(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc);
854 
855 	/* Pass in all sorts of things other than the property ID. */
856 	num_props_raw[0] = 1;
857 	do_ioctl_err(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc, ENOENT);
858 	props_raw[0] = pipe->crtc_id;
859 	do_ioctl_err(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc, ENOENT);
860 	props_raw[0] = plane->drm_plane->plane_id;
861 	do_ioctl_err(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc, ENOENT);
862 	props_raw[0] = output->id;
863 	do_ioctl_err(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc, ENOENT);
864 	props_raw[0] = pipe->values[IGT_CRTC_MODE_ID];
865 	do_ioctl_err(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc, ENOENT);
866 
867 	/* Valid property, valid value. */
868 
869 	for (i = 0; i < ARRAY_SIZE(props_raw); i++) {
870 		props_raw[i] = pipe->props[IGT_CRTC_MODE_ID];
871 		values_raw[i] = pipe->values[IGT_CRTC_MODE_ID];
872 	}
873 	do_ioctl(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc);
874 
875 	/* Setting the same thing multiple times is OK. */
876 	for (i = 0; i < ARRAY_SIZE(obj_raw); i++)
877 		num_props_raw[i] = ARRAY_SIZE(props_raw) / ARRAY_SIZE(obj_raw);
878 	do_ioctl(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc);
879 	ioc.count_objs = ARRAY_SIZE(obj_raw);
880 	do_ioctl(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc);
881 
882 	/* Pass a series of outlandish addresses. */
883 	ioc.objs_ptr = 0;
884 	do_ioctl_err(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc, EFAULT);
885 
886 	ioc.objs_ptr = (uintptr_t) obj_raw;
887 	ioc.count_props_ptr = 0;
888 	do_ioctl_err(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc, EFAULT);
889 
890 	ioc.count_props_ptr = (uintptr_t) num_props_raw;
891 	ioc.props_ptr = 0;
892 	do_ioctl_err(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc, EFAULT);
893 
894 	ioc.props_ptr = (uintptr_t) props_raw;
895 	ioc.prop_values_ptr = 0;
896 	do_ioctl_err(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc, EFAULT);
897 
898 	ioc.prop_values_ptr = (uintptr_t) values_raw;
899 	do_ioctl(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc);
900 
901 	/* Attempt to overflow and/or trip various boundary conditions. */
902 	ioc.count_objs = UINT32_MAX / sizeof(uint32_t);
903 	do_ioctl_err(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc, ENOENT);
904 
905 	ioc.count_objs = ARRAY_SIZE(obj_raw);
906 	ioc.objs_ptr = UINT64_MAX - sizeof(uint32_t);
907 	do_ioctl_err(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc, EFAULT);
908 	ioc.count_objs = 1;
909 	ioc.objs_ptr = UINT64_MAX - sizeof(uint32_t);
910 	do_ioctl_err(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc, EFAULT);
911 
912 	num_props_raw[0] = UINT32_MAX / sizeof(uint32_t);
913 	do_ioctl_err(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc, EFAULT);
914 	num_props_raw[0] = UINT32_MAX - 1;
915 	do_ioctl_err(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc, EFAULT);
916 
917 	for (i = 0; i < ARRAY_SIZE(obj_raw); i++)
918 		num_props_raw[i] = (UINT32_MAX / ARRAY_SIZE(obj_raw)) + 1;
919 	do_ioctl_err(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc, EFAULT);
920 	for (i = 0; i < ARRAY_SIZE(obj_raw); i++)
921 		num_props_raw[i] = ARRAY_SIZE(props_raw) / ARRAY_SIZE(obj_raw);
922 	do_ioctl_err(display->drm_fd, DRM_IOCTL_MODE_ATOMIC, &ioc, EFAULT);
923 }
924 
atomic_setup(igt_display_t * display,enum pipe pipe,igt_output_t * output,igt_plane_t * primary,struct igt_fb * fb)925 static void atomic_setup(igt_display_t *display, enum pipe pipe, igt_output_t *output, igt_plane_t *primary, struct igt_fb *fb)
926 {
927 	igt_output_set_pipe(output, pipe);
928 	igt_plane_set_fb(primary, fb);
929 
930 	crtc_commit(primary->pipe, primary, COMMIT_ATOMIC, ATOMIC_RELAX_NONE);
931 }
932 
atomic_clear(igt_display_t * display,enum pipe pipe,igt_plane_t * primary,igt_output_t * output)933 static void atomic_clear(igt_display_t *display, enum pipe pipe, igt_plane_t *primary, igt_output_t *output)
934 {
935 	igt_plane_t *plane;
936 
937 	for_each_plane_on_pipe(display, pipe, plane) {
938 		igt_plane_set_fb(plane, NULL);
939 		igt_plane_set_position(plane, 0, 0);
940 	}
941 
942 	igt_output_set_pipe(output, PIPE_NONE);
943 	crtc_commit(primary->pipe, primary, COMMIT_ATOMIC, ATOMIC_RELAX_NONE);
944 }
945 
946 igt_main
947 {
948 	igt_display_t display;
949 	enum pipe pipe = PIPE_NONE;
950 	igt_pipe_t *pipe_obj;
951 	igt_output_t *output = NULL;
952 	igt_plane_t *primary = NULL;
953 	drmModeModeInfo *mode;
954 	struct igt_fb fb;
955 
956 	igt_fixture {
957 		display.drm_fd = drm_open_driver_master(DRIVER_ANY);
958 
959 		kmstest_set_vt_graphics_mode();
960 
961 		igt_display_require(&display, display.drm_fd);
962 		igt_require(display.is_atomic);
963 		igt_display_require_output(&display);
964 
965 		for_each_pipe_with_valid_output(&display, pipe, output)
966 			break;
967 
968 		pipe_obj = &display.pipes[pipe];
969 		primary = igt_pipe_get_plane_type(pipe_obj, DRM_PLANE_TYPE_PRIMARY);
970 
971 		mode = igt_output_get_mode(output);
972 
973 		igt_create_pattern_fb(display.drm_fd,
974 				      mode->hdisplay, mode->vdisplay,
975 				      plane_get_igt_format(primary),
976 				      LOCAL_DRM_FORMAT_MOD_NONE, &fb);
977 	}
978 
979 	igt_subtest("plane_overlay_legacy") {
980 		igt_plane_t *overlay =
981 			igt_pipe_get_plane_type(pipe_obj, DRM_PLANE_TYPE_OVERLAY);
982 
983 		igt_require(overlay);
984 
985 		atomic_setup(&display, pipe, output, primary, &fb);
986 		plane_overlay(pipe_obj, output, overlay);
987 	}
988 
989 	igt_subtest("plane_primary_legacy") {
990 		atomic_setup(&display, pipe, output, primary, &fb);
991 
992 		plane_primary(pipe_obj, primary, &fb);
993 	}
994 
995 	igt_subtest("plane_primary_overlay_zpos") {
996 		uint32_t format_primary = DRM_FORMAT_ARGB8888;
997 		uint32_t format_overlay = DRM_FORMAT_ARGB1555;
998 
999 		igt_plane_t *overlay =
1000 			igt_pipe_get_plane_type(pipe_obj, DRM_PLANE_TYPE_OVERLAY);
1001 
1002 		igt_require(overlay);
1003 		igt_require(igt_plane_has_prop(primary, IGT_PLANE_ZPOS));
1004 		igt_require(igt_plane_has_prop(overlay, IGT_PLANE_ZPOS));
1005 
1006 		igt_require(igt_plane_has_format_mod(primary, format_primary, 0x0));
1007 		igt_require(igt_plane_has_format_mod(overlay, format_overlay, 0x0));
1008 
1009 		igt_output_set_pipe(output, pipe);
1010 		plane_primary_overlay_zpos(pipe_obj, output, primary, overlay,
1011 					   format_primary, format_overlay);
1012 	}
1013 
1014 	igt_subtest("test_only") {
1015 		atomic_clear(&display, pipe, primary, output);
1016 
1017 		test_only(pipe_obj, primary, output);
1018 	}
1019 	igt_subtest("plane_cursor_legacy") {
1020 		igt_plane_t *cursor =
1021 			igt_pipe_get_plane_type(pipe_obj, DRM_PLANE_TYPE_CURSOR);
1022 
1023 		igt_require(cursor);
1024 
1025 		atomic_setup(&display, pipe, output, primary, &fb);
1026 		plane_cursor(pipe_obj, output, cursor);
1027 	}
1028 
1029 	igt_subtest("plane_invalid_params") {
1030 		atomic_setup(&display, pipe, output, primary, &fb);
1031 
1032 		plane_invalid_params(pipe_obj, output, primary, &fb);
1033 	}
1034 
1035 	igt_subtest("plane_invalid_params_fence") {
1036 		atomic_setup(&display, pipe, output, primary, &fb);
1037 
1038 		plane_invalid_params_fence(pipe_obj, output, primary);
1039 	}
1040 
1041 	igt_subtest("crtc_invalid_params") {
1042 		atomic_setup(&display, pipe, output, primary, &fb);
1043 
1044 		crtc_invalid_params(pipe_obj, output, primary, &fb);
1045 	}
1046 
1047 	igt_subtest("crtc_invalid_params_fence") {
1048 		atomic_setup(&display, pipe, output, primary, &fb);
1049 
1050 		crtc_invalid_params_fence(pipe_obj, output, primary, &fb);
1051 	}
1052 
1053 	igt_subtest("atomic_invalid_params") {
1054 		atomic_setup(&display, pipe, output, primary, &fb);
1055 
1056 		atomic_invalid_params(pipe_obj, primary, output, &fb);
1057 	}
1058 
1059 	igt_fixture {
1060 		atomic_clear(&display, pipe, primary, output);
1061 		igt_remove_fb(display.drm_fd, &fb);
1062 
1063 		igt_display_fini(&display);
1064 	}
1065 }
1066