xref: /aosp_15_r20/external/igt-gpu-tools/tests/kms_lease.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
1 /*
2  * Copyright © 2017 Keith Packard
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 /** @file kms_lease.c
25  *
26  * This is a test of DRM leases
27  */
28 
29 
30 #include "igt.h"
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <fcntl.h>
35 #include <inttypes.h>
36 #include <errno.h>
37 #include <time.h>
38 #include <sys/poll.h>
39 #include <sys/stat.h>
40 #include <sys/time.h>
41 #include <sys/wait.h>
42 
43 #include <libudev.h>
44 
45 #include <drm.h>
46 #include "igt_device.h"
47 
48 IGT_TEST_DESCRIPTION("Test of CreateLease.");
49 
50 struct local_drm_mode_create_lease {
51         /** Pointer to array of object ids (__u32) */
52         __u64 object_ids;
53         /** Number of object ids */
54         __u32 object_count;
55         /** flags for new FD (O_CLOEXEC, etc) */
56         __u32 flags;
57 
58         /** Return: unique identifier for lessee. */
59         __u32 lessee_id;
60         /** Return: file descriptor to new drm_master file */
61         __u32 fd;
62 };
63 
64 struct local_drm_mode_list_lessees {
65         /** Number of lessees.
66          * On input, provides length of the array.
67          * On output, provides total number. No
68          * more than the input number will be written
69          * back, so two calls can be used to get
70          * the size and then the data.
71          */
72         __u32 count_lessees;
73         __u32 pad;
74 
75         /** Pointer to lessees.
76          * pointer to __u64 array of lessee ids
77          */
78         __u64 lessees_ptr;
79 };
80 
81 struct local_drm_mode_get_lease {
82         /** Number of leased objects.
83          * On input, provides length of the array.
84          * On output, provides total number. No
85          * more than the input number will be written
86          * back, so two calls can be used to get
87          * the size and then the data.
88          */
89         __u32 count_objects;
90         __u32 pad;
91 
92         /** Pointer to objects.
93          * pointer to __u32 array of object ids
94          */
95         __u64 objects_ptr;
96 };
97 
98 /**
99  * Revoke lease
100  */
101 struct local_drm_mode_revoke_lease {
102         /** Unique ID of lessee
103          */
104         __u32 lessee_id;
105 };
106 
107 
108 #define LOCAL_DRM_IOCTL_MODE_CREATE_LEASE     DRM_IOWR(0xC6, struct local_drm_mode_create_lease)
109 #define LOCAL_DRM_IOCTL_MODE_LIST_LESSEES     DRM_IOWR(0xC7, struct local_drm_mode_list_lessees)
110 #define LOCAL_DRM_IOCTL_MODE_GET_LEASE        DRM_IOWR(0xC8, struct local_drm_mode_get_lease)
111 #define LOCAL_DRM_IOCTL_MODE_REVOKE_LEASE     DRM_IOWR(0xC9, struct local_drm_mode_revoke_lease)
112 
113 typedef struct {
114 	int fd;
115 	uint32_t lessee_id;
116 	igt_display_t display;
117 	struct igt_fb primary_fb;
118 	igt_output_t *output;
119 	drmModeModeInfo *mode;
120 } lease_t;
121 
122 typedef struct {
123 	lease_t master;
124 	enum pipe pipe;
125 	uint32_t crtc_id;
126 	uint32_t connector_id;
127 	uint32_t plane_id;
128 } data_t;
129 
pipe_to_crtc_id(igt_display_t * display,enum pipe pipe)130 static uint32_t pipe_to_crtc_id(igt_display_t *display, enum pipe pipe)
131 {
132 	return display->pipes[pipe].crtc_id;
133 }
134 
crtc_id_to_pipe(igt_display_t * display,uint32_t crtc_id)135 static enum pipe crtc_id_to_pipe(igt_display_t *display, uint32_t crtc_id)
136 {
137 	enum pipe pipe;
138 
139 	for (pipe = 0; pipe < display->n_pipes; pipe++)
140 		if (display->pipes[pipe].crtc_id == crtc_id)
141 			return pipe;
142 	return -1;
143 }
144 
connector_id_to_output(igt_display_t * display,uint32_t connector_id)145 static igt_output_t *connector_id_to_output(igt_display_t *display, uint32_t connector_id)
146 {
147 	drmModeConnector		connector;
148 
149 	connector.connector_id = connector_id;
150 	return igt_output_from_connector(display, &connector);
151 }
152 
prepare_crtc(lease_t * lease,uint32_t connector_id,uint32_t crtc_id)153 static int prepare_crtc(lease_t *lease, uint32_t connector_id, uint32_t crtc_id)
154 {
155 	drmModeModeInfo *mode;
156 	igt_display_t *display = &lease->display;
157 	igt_output_t *output = connector_id_to_output(display, connector_id);
158 	enum pipe pipe = crtc_id_to_pipe(display, crtc_id);
159 	igt_plane_t *primary;
160 	int ret;
161 
162 	if (!output)
163 		return -ENOENT;
164 
165 	/* select the pipe we want to use */
166 	igt_output_set_pipe(output, pipe);
167 
168 	/* create and set the primary plane fb */
169 	mode = igt_output_get_mode(output);
170 	igt_create_color_fb(lease->fd, mode->hdisplay, mode->vdisplay,
171 			    DRM_FORMAT_XRGB8888,
172 			    LOCAL_DRM_FORMAT_MOD_NONE,
173 			    0.0, 0.0, 0.0,
174 			    &lease->primary_fb);
175 
176 	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
177 	igt_plane_set_fb(primary, &lease->primary_fb);
178 
179 	ret = igt_display_try_commit2(display, COMMIT_LEGACY);
180 
181 	if (ret)
182 		return ret;
183 
184 	igt_wait_for_vblank(lease->fd, pipe);
185 
186 	lease->output = output;
187 	lease->mode = mode;
188 	return 0;
189 }
190 
cleanup_crtc(lease_t * lease,igt_output_t * output)191 static void cleanup_crtc(lease_t *lease, igt_output_t *output)
192 {
193 	igt_display_t *display = &lease->display;
194 	igt_plane_t *primary;
195 
196 	igt_remove_fb(lease->fd, &lease->primary_fb);
197 
198 	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
199 	igt_plane_set_fb(primary, NULL);
200 
201 	igt_output_set_pipe(output, PIPE_ANY);
202 	igt_display_commit(display);
203 }
204 
create_lease(int fd,struct local_drm_mode_create_lease * mcl)205 static int create_lease(int fd, struct local_drm_mode_create_lease *mcl)
206 {
207 	int err = 0;
208 
209 	if (igt_ioctl(fd, LOCAL_DRM_IOCTL_MODE_CREATE_LEASE, mcl))
210 		err = -errno;
211 	return err;
212 }
213 
revoke_lease(int fd,struct local_drm_mode_revoke_lease * mrl)214 static int revoke_lease(int fd, struct local_drm_mode_revoke_lease *mrl)
215 {
216 	int err = 0;
217 
218 	if (igt_ioctl(fd, LOCAL_DRM_IOCTL_MODE_REVOKE_LEASE, mrl))
219 		err = -errno;
220 	return err;
221 }
222 
list_lessees(int fd,struct local_drm_mode_list_lessees * mll)223 static int list_lessees(int fd, struct local_drm_mode_list_lessees *mll)
224 {
225 	int err = 0;
226 
227 	if (igt_ioctl(fd, LOCAL_DRM_IOCTL_MODE_LIST_LESSEES, mll))
228 		err = -errno;
229 	return err;
230 }
231 
get_lease(int fd,struct local_drm_mode_get_lease * mgl)232 static int get_lease(int fd, struct local_drm_mode_get_lease *mgl)
233 {
234 	int err = 0;
235 
236 	if (igt_ioctl(fd, LOCAL_DRM_IOCTL_MODE_GET_LEASE, mgl))
237 		err = -errno;
238 	return err;
239 }
240 
make_lease(data_t * data,lease_t * lease)241 static int make_lease(data_t *data, lease_t *lease)
242 {
243 	uint32_t object_ids[3];
244 	struct local_drm_mode_create_lease mcl;
245 	int ret;
246 
247 	mcl.object_ids = (uint64_t) (uintptr_t) &object_ids[0];
248 	mcl.object_count = 0;
249 	mcl.flags = 0;
250 
251 	object_ids[mcl.object_count++] = data->connector_id;
252 	object_ids[mcl.object_count++] = data->crtc_id;
253 	/* We use universal planes, must add the primary plane */
254 	object_ids[mcl.object_count++] = data->plane_id;
255 
256 	ret = create_lease(data->master.fd, &mcl);
257 
258 	if (ret)
259 		return ret;
260 
261 	lease->fd = mcl.fd;
262 	lease->lessee_id = mcl.lessee_id;
263 	return 0;
264 }
265 
terminate_lease(lease_t * lease)266 static void terminate_lease(lease_t *lease)
267 {
268 	close(lease->fd);
269 }
270 
paint_fb(int drm_fd,struct igt_fb * fb,const char * test_name,const char * mode_format_str,const char * connector_str,const char * pipe_str)271 static int paint_fb(int drm_fd, struct igt_fb *fb, const char *test_name,
272 		    const char *mode_format_str, const char *connector_str, const char *pipe_str)
273 {
274 	cairo_t *cr;
275 
276 	cr = igt_get_cairo_ctx(drm_fd, fb);
277 
278 	igt_paint_color_gradient(cr, 0, 0, fb->width, fb->height, 1, 1, 1);
279 	igt_paint_test_pattern(cr, fb->width, fb->height);
280 
281 	cairo_move_to(cr, fb->width / 2, fb->height / 2);
282 	cairo_set_font_size(cr, 36);
283 	igt_cairo_printf_line(cr, align_hcenter, 10, "%s", test_name);
284 	igt_cairo_printf_line(cr, align_hcenter, 10, "%s", mode_format_str);
285 	igt_cairo_printf_line(cr, align_hcenter, 10, "%s", connector_str);
286 	igt_cairo_printf_line(cr, align_hcenter, 10, "%s", pipe_str);
287 
288 	cairo_destroy(cr);
289 
290 	return 0;
291 }
292 
simple_lease(data_t * data)293 static void simple_lease(data_t *data)
294 {
295 	lease_t lease;
296 
297 	/* Create a valid lease */
298 	igt_assert_eq(make_lease(data, &lease), 0);
299 
300 	igt_display_require(&lease.display, lease.fd);
301 
302 	/* Set a mode on the leased output */
303 	igt_assert_eq(0, prepare_crtc(&lease, data->connector_id, data->crtc_id));
304 
305 	/* Paint something attractive */
306 	paint_fb(lease.fd, &lease.primary_fb, "simple_lease",
307 		 lease.mode->name, igt_output_name(lease.output), kmstest_pipe_name(data->pipe));
308 	igt_debug_wait_for_keypress("lease");
309 	cleanup_crtc(&lease,
310 		     connector_id_to_output(&lease.display, data->connector_id));
311 
312 	terminate_lease(&lease);
313 }
314 
page_flip_implicit_plane(data_t * data)315 static void page_flip_implicit_plane(data_t *data)
316 {
317 	uint32_t object_ids[3];
318 	struct local_drm_mode_create_lease mcl;
319 	drmModePlaneRes *plane_resources;
320 	uint32_t wrong_plane_id = 0;
321 	int i;
322 
323 	/* find a plane which isn't the primary one for us */
324 	plane_resources = drmModeGetPlaneResources(data->master.fd);
325 	for (i = 0; i < plane_resources->count_planes; i++) {
326 		if (plane_resources->planes[i] != data->plane_id) {
327 			wrong_plane_id = plane_resources->planes[i];
328 			break;
329 		}
330 	}
331 	drmModeFreePlaneResources(plane_resources);
332 	igt_require(wrong_plane_id);
333 
334 	mcl.object_ids = (uint64_t) (uintptr_t) &object_ids[0];
335 	mcl.object_count = 0;
336 	mcl.flags = 0;
337 
338 	object_ids[mcl.object_count++] = data->connector_id;
339 	object_ids[mcl.object_count++] = data->crtc_id;
340 
341 	drmSetClientCap(data->master.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 0);
342 	do_or_die(create_lease(data->master.fd, &mcl));
343 	drmSetClientCap(data->master.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
344 
345 	/* Set a mode on the leased output */
346 	igt_assert_eq(0, prepare_crtc(&data->master, data->connector_id, data->crtc_id));
347 
348 	/* sanity check */
349 	do_or_die(drmModePageFlip(data->master.fd, data->crtc_id,
350 			      data->master.primary_fb.fb_id,
351 			      0, NULL));
352 	igt_wait_for_vblank_count(data->master.fd,
353 				  crtc_id_to_pipe(&data->master.display, data->crtc_id),
354 				  1);
355 	do_or_die(drmModePageFlip(mcl.fd, data->crtc_id,
356 			      data->master.primary_fb.fb_id,
357 			      0, NULL));
358 	close(mcl.fd);
359 
360 	object_ids[mcl.object_count++] = wrong_plane_id;
361 	do_or_die(create_lease(data->master.fd, &mcl));
362 
363 	igt_wait_for_vblank_count(data->master.fd,
364 				  crtc_id_to_pipe(&data->master.display, data->crtc_id),
365 				  1);
366 	igt_assert_eq(drmModePageFlip(mcl.fd, data->crtc_id,
367 				      data->master.primary_fb.fb_id,
368 				      0, NULL),
369 		      -EACCES);
370 	close(mcl.fd);
371 
372 	cleanup_crtc(&data->master,
373 		     connector_id_to_output(&data->master.display, data->connector_id));
374 }
375 
setcrtc_implicit_plane(data_t * data)376 static void setcrtc_implicit_plane(data_t *data)
377 {
378 	uint32_t object_ids[3];
379 	struct local_drm_mode_create_lease mcl;
380 	drmModePlaneRes *plane_resources;
381 	uint32_t wrong_plane_id = 0;
382 	igt_output_t *output =
383 		connector_id_to_output(&data->master.display,
384 				       data->connector_id);
385 	drmModeModeInfo *mode = igt_output_get_mode(output);
386 	int i;
387 
388 	/* find a plane which isn't the primary one for us */
389 	plane_resources = drmModeGetPlaneResources(data->master.fd);
390 	for (i = 0; i < plane_resources->count_planes; i++) {
391 		if (plane_resources->planes[i] != data->plane_id) {
392 			wrong_plane_id = plane_resources->planes[i];
393 			break;
394 		}
395 	}
396 	drmModeFreePlaneResources(plane_resources);
397 	igt_require(wrong_plane_id);
398 
399 	mcl.object_ids = (uint64_t) (uintptr_t) &object_ids[0];
400 	mcl.object_count = 0;
401 	mcl.flags = 0;
402 
403 	object_ids[mcl.object_count++] = data->connector_id;
404 	object_ids[mcl.object_count++] = data->crtc_id;
405 
406 	drmSetClientCap(data->master.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 0);
407 	do_or_die(create_lease(data->master.fd, &mcl));
408 	drmSetClientCap(data->master.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
409 
410 	/* Set a mode on the leased output */
411 	igt_assert_eq(0, prepare_crtc(&data->master, data->connector_id, data->crtc_id));
412 
413 	/* sanity check */
414 	do_or_die(drmModeSetCrtc(data->master.fd, data->crtc_id, -1,
415 				 0, 0, object_ids, 1, mode));
416 	do_or_die(drmModeSetCrtc(mcl.fd, data->crtc_id, -1,
417 				 0, 0, object_ids, 1, mode));
418 	close(mcl.fd);
419 
420 	object_ids[mcl.object_count++] = wrong_plane_id;
421 	do_or_die(create_lease(data->master.fd, &mcl));
422 
423 	igt_assert_eq(drmModeSetCrtc(mcl.fd, data->crtc_id, -1,
424 				     0, 0, object_ids, 1, mode),
425 		      -EACCES);
426 	/* make sure we are allowed to turn the CRTC off */
427 	do_or_die(drmModeSetCrtc(mcl.fd, data->crtc_id,
428 				 0, 0, 0, NULL, 0, NULL));
429 	close(mcl.fd);
430 
431 	cleanup_crtc(&data->master,
432 		     connector_id_to_output(&data->master.display, data->connector_id));
433 }
434 
cursor_implicit_plane(data_t * data)435 static void cursor_implicit_plane(data_t *data)
436 {
437 	uint32_t object_ids[3];
438 	struct local_drm_mode_create_lease mcl;
439 
440 	mcl.object_ids = (uint64_t) (uintptr_t) &object_ids[0];
441 	mcl.object_count = 0;
442 	mcl.flags = 0;
443 
444 	object_ids[mcl.object_count++] = data->connector_id;
445 	object_ids[mcl.object_count++] = data->crtc_id;
446 
447 	drmSetClientCap(data->master.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 0);
448 	do_or_die(create_lease(data->master.fd, &mcl));
449 	drmSetClientCap(data->master.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
450 
451 	/* Set a mode on the leased output */
452 	igt_assert_eq(0, prepare_crtc(&data->master, data->connector_id, data->crtc_id));
453 
454 	/* sanity check */
455 	do_or_die(drmModeSetCursor(data->master.fd, data->crtc_id, 0, 0, 0));
456 	do_or_die(drmModeSetCursor(mcl.fd, data->crtc_id, 0, 0, 0));
457 	close(mcl.fd);
458 
459 	/* primary plane is never the cursor */
460 	object_ids[mcl.object_count++] = data->plane_id;
461 	do_or_die(create_lease(data->master.fd, &mcl));
462 
463 	igt_assert_eq(drmModeSetCursor(mcl.fd, data->crtc_id, 0, 0, 0),
464 		      -EACCES);
465 	close(mcl.fd);
466 
467 	cleanup_crtc(&data->master,
468 		     connector_id_to_output(&data->master.display, data->connector_id));
469 }
470 
atomic_implicit_crtc(data_t * data)471 static void atomic_implicit_crtc(data_t *data)
472 {
473 	uint32_t object_ids[3];
474 	struct local_drm_mode_create_lease mcl;
475 	drmModeRes *resources;
476 	drmModeObjectPropertiesPtr props;
477 	uint32_t wrong_crtc_id = 0;
478 	uint32_t crtc_id_prop = 0;
479 	drmModeAtomicReqPtr req = NULL;
480 	int ret;
481 
482 	igt_require(data->master.display.is_atomic);
483 
484 	mcl.object_ids = (uint64_t) (uintptr_t) &object_ids[0];
485 	mcl.object_count = 0;
486 	mcl.flags = 0;
487 
488 	object_ids[mcl.object_count++] = data->connector_id;
489 	object_ids[mcl.object_count++] = data->plane_id;
490 
491 	/* find a plane which isn't the primary one for us */
492 	resources = drmModeGetResources(data->master.fd);
493 	igt_assert(resources);
494 	for (int i = 0; i < resources->count_crtcs; i++) {
495 		if (resources->crtcs[i] != data->crtc_id) {
496 			wrong_crtc_id = resources->crtcs[i];
497 			break;
498 		}
499 	}
500 	drmModeFreeResources(resources);
501 	igt_require(wrong_crtc_id);
502 	object_ids[mcl.object_count++] = wrong_crtc_id;
503 
504 	/* find the CRTC_ID prop, it's global */
505 	props = drmModeObjectGetProperties(data->master.fd, data->plane_id,
506 					   DRM_MODE_OBJECT_PLANE);
507 	igt_assert(props);
508 	for (int i = 0; i < props->count_props; i++) {
509 		drmModePropertyPtr prop = drmModeGetProperty(data->master.fd,
510 							     props->props[i]);
511 		if (strcmp(prop->name, "CRTC_ID") == 0)
512 			crtc_id_prop = props->props[i];
513 
514 		printf("prop name %s, prop id %u, prop id %u\n",
515 		       prop->name, props->props[i], prop->prop_id);
516 		drmModeFreeProperty(prop);
517 		if (crtc_id_prop)
518 			break;
519 	}
520 	drmModeFreeObjectProperties(props);
521 	igt_assert(crtc_id_prop);
522 
523 	do_or_die(create_lease(data->master.fd, &mcl));
524 	do_or_die(drmSetClientCap(mcl.fd, DRM_CLIENT_CAP_ATOMIC, 1));
525 
526 	/* check CRTC_ID property on the plane */
527 	req = drmModeAtomicAlloc();
528 	igt_assert(req);
529 	ret = drmModeAtomicAddProperty(req, data->plane_id,
530 				       crtc_id_prop, data->crtc_id);
531 	igt_assert(ret >= 0);
532 
533 	/* sanity check */
534 	ret = drmModeAtomicCommit(data->master.fd, req, DRM_MODE_ATOMIC_TEST_ONLY, NULL);
535 	igt_assert(ret == 0 || ret == -EINVAL);
536 
537 	ret = drmModeAtomicCommit(mcl.fd, req, DRM_MODE_ATOMIC_TEST_ONLY, NULL);
538 	igt_assert(ret == -EACCES);
539 	drmModeAtomicFree(req);
540 
541 	/* check CRTC_ID property on the connector */
542 	req = drmModeAtomicAlloc();
543 	igt_assert(req);
544 	ret = drmModeAtomicAddProperty(req, data->connector_id,
545 				       crtc_id_prop, data->crtc_id);
546 	igt_assert(ret >= 0);
547 
548 	/* sanity check */
549 	ret = drmModeAtomicCommit(data->master.fd, req, DRM_MODE_ATOMIC_TEST_ONLY, NULL);
550 	igt_assert(ret == 0 || ret == -EINVAL);
551 
552 	ret = drmModeAtomicCommit(mcl.fd, req, DRM_MODE_ATOMIC_TEST_ONLY, NULL);
553 	igt_assert(ret == -EACCES);
554 	drmModeAtomicFree(req);
555 
556 	close(mcl.fd);
557 }
558 
559 /* Test listing lessees */
lessee_list(data_t * data)560 static void lessee_list(data_t *data)
561 {
562 	lease_t lease;
563 	struct local_drm_mode_list_lessees mll;
564 	uint32_t lessees[1];
565 
566 	mll.pad = 0;
567 
568 	/* Create a valid lease */
569 	igt_assert_eq(make_lease(data, &lease), 0);
570 
571 	/* check for nested leases */
572 	mll.count_lessees = 0;
573 	mll.lessees_ptr = 0;
574 	igt_assert_eq(list_lessees(lease.fd, &mll), 0);
575 	igt_assert_eq(mll.count_lessees, 0);
576 
577 	/* Get the number of lessees */
578 	mll.count_lessees = 0;
579 	mll.lessees_ptr = 0;
580 	igt_assert_eq(list_lessees(data->master.fd, &mll), 0);
581 
582 	/* Make sure there's a single lessee */
583 	igt_assert_eq(mll.count_lessees, 1);
584 
585 	/* invalid ptr */
586 	igt_assert_eq(list_lessees(data->master.fd, &mll), -EFAULT);
587 
588 	mll.lessees_ptr = (uint64_t) (uintptr_t) &lessees[0];
589 
590 	igt_assert_eq(list_lessees(data->master.fd, &mll), 0);
591 
592 	/* Make sure there's a single lessee */
593 	igt_assert_eq(mll.count_lessees, 1);
594 
595 	/* Make sure the listed lease is the same as the one we created */
596 	igt_assert_eq(lessees[0], lease.lessee_id);
597 
598 	/* invalid pad */
599 	mll.pad = -1;
600 	igt_assert_eq(list_lessees(data->master.fd, &mll), -EINVAL);
601 	mll.pad = 0;
602 
603 	terminate_lease(&lease);
604 
605 	/* Make sure the lease is gone */
606 	igt_assert_eq(list_lessees(data->master.fd, &mll), 0);
607 	igt_assert_eq(mll.count_lessees, 0);
608 }
609 
610 /* Test getting the contents of a lease */
lease_get(data_t * data)611 static void lease_get(data_t *data)
612 {
613 	lease_t lease;
614 	struct local_drm_mode_get_lease mgl;
615 	int num_leased_obj = 3;
616 	uint32_t objects[num_leased_obj];
617 	int o;
618 
619 	mgl.pad = 0;
620 
621 	/* Create a valid lease */
622 	igt_assert_eq(make_lease(data, &lease), 0);
623 
624 	/* Get the number of objects */
625 	mgl.count_objects = 0;
626 	mgl.objects_ptr = 0;
627 	igt_assert_eq(get_lease(lease.fd, &mgl), 0);
628 
629 	/* Make sure it's 2 */
630 	igt_assert_eq(mgl.count_objects, num_leased_obj);
631 
632 	/* Get the objects */
633 	mgl.objects_ptr = (uint64_t) (uintptr_t) objects;
634 
635 	igt_assert_eq(get_lease(lease.fd, &mgl), 0);
636 
637 	/* Make sure it's 2 */
638 	igt_assert_eq(mgl.count_objects, num_leased_obj);
639 
640 	/* Make sure we got the connector, crtc and plane back */
641 	for (o = 0; o < num_leased_obj; o++)
642 		if (objects[o] == data->connector_id)
643 			break;
644 
645 	igt_assert_neq(o, num_leased_obj);
646 
647 	for (o = 0; o < num_leased_obj; o++)
648 		if (objects[o] == data->crtc_id)
649 			break;
650 
651 	igt_assert_neq(o, num_leased_obj);
652 
653 	for (o = 0; o < num_leased_obj; o++)
654 		if (objects[o] == data->plane_id)
655 			break;
656 
657 	igt_assert_neq(o, num_leased_obj);
658 
659 	/* invalid pad */
660 	mgl.pad = -1;
661 	igt_assert_eq(get_lease(lease.fd, &mgl), -EINVAL);
662 	mgl.pad = 0;
663 
664 	/* invalid pointer */
665 	mgl.objects_ptr = 0;
666 	igt_assert_eq(get_lease(lease.fd, &mgl), -EFAULT);
667 
668 	terminate_lease(&lease);
669 }
670 
lease_unleased_crtc(data_t * data)671 static void lease_unleased_crtc(data_t *data)
672 {
673 	lease_t lease;
674 	enum pipe p;
675 	uint32_t bad_crtc_id;
676 	drmModeCrtc *crtc;
677 	int ret;
678 
679 	/* Create a valid lease */
680 	igt_assert_eq(make_lease(data, &lease), 0);
681 
682 	igt_display_require(&lease.display, lease.fd);
683 
684 	/* Find another CRTC that we don't control */
685 	bad_crtc_id = 0;
686 	for (p = 0; bad_crtc_id == 0 && p < data->master.display.n_pipes; p++) {
687 		if (pipe_to_crtc_id(&data->master.display, p) != data->crtc_id)
688 			bad_crtc_id = pipe_to_crtc_id(&data->master.display, p);
689 	}
690 
691 	/* Give up if there isn't another crtc */
692 	igt_skip_on(bad_crtc_id == 0);
693 
694 	/* sanity check */
695 	ret = drmModeSetCrtc(lease.fd, data->crtc_id, 0, 0, 0, NULL, 0, NULL);
696 	igt_assert_eq(ret, 0);
697 	crtc = drmModeGetCrtc(lease.fd, data->crtc_id);
698 	igt_assert(crtc);
699 	drmModeFreeCrtc(crtc);
700 
701 	/* Attempt to use the unleased crtc id. We need raw ioctl to bypass the
702 	 * igt_kms helpers.
703 	 */
704 	ret = drmModeSetCrtc(lease.fd, bad_crtc_id, 0, 0, 0, NULL, 0, NULL);
705 	igt_assert_eq(ret, -ENOENT);
706 	crtc = drmModeGetCrtc(lease.fd, bad_crtc_id);
707 	igt_assert(!crtc);
708 	igt_assert_eq(errno, ENOENT);
709 	drmModeFreeCrtc(crtc);
710 
711 	terminate_lease(&lease);
712 }
713 
lease_unleased_connector(data_t * data)714 static void lease_unleased_connector(data_t *data)
715 {
716 	lease_t lease;
717 	int o;
718 	uint32_t bad_connector_id;
719 	drmModeConnector *c;
720 
721 	/* Create a valid lease */
722 	igt_assert_eq(make_lease(data, &lease), 0);
723 
724 	igt_display_require(&lease.display, lease.fd);
725 
726 	/* Find another connector that we don't control */
727 	bad_connector_id = 0;
728 	for (o = 0; bad_connector_id == 0 && o < data->master.display.n_outputs; o++) {
729 		if (data->master.display.outputs[o].id != data->connector_id)
730 			bad_connector_id = data->master.display.outputs[o].id;
731 	}
732 
733 	/* Give up if there isn't another connector */
734 	igt_skip_on(bad_connector_id == 0);
735 
736 	/* sanity check */
737 	c = drmModeGetConnector(lease.fd, data->connector_id);
738 	igt_assert(c);
739 
740 	/* Attempt to use the unleased connector id. Note that the
741 	 */
742 	c = drmModeGetConnector(lease.fd, bad_connector_id);
743 	igt_assert(!c);
744 	igt_assert_eq(errno, ENOENT);
745 
746 	terminate_lease(&lease);
747 }
748 
749 /* Test revocation of lease */
lease_revoke(data_t * data)750 static void lease_revoke(data_t *data)
751 {
752 	lease_t lease;
753 	struct local_drm_mode_revoke_lease mrl;
754 	int ret;
755 
756 	/* Create a valid lease */
757 	igt_assert_eq(make_lease(data, &lease), 0);
758 
759 	igt_display_require(&lease.display, lease.fd);
760 
761 	/* try to revoke an invalid lease */
762 	mrl.lessee_id = 0;
763 	igt_assert_eq(revoke_lease(data->master.fd, &mrl), -ENOENT);
764 
765 	/* try to revoke with the wrong fd */
766 	mrl.lessee_id = lease.lessee_id;
767 	igt_assert_eq(revoke_lease(lease.fd, &mrl), -EACCES);
768 
769 	/* Revoke the lease using the master fd */
770 	mrl.lessee_id = lease.lessee_id;
771 	igt_assert_eq(revoke_lease(data->master.fd, &mrl), 0);
772 
773 	/* Try to use the leased objects */
774 	ret = prepare_crtc(&lease, data->connector_id, data->crtc_id);
775 
776 	/* Ensure that the expected error is returned */
777 	igt_assert_eq(ret, -ENOENT);
778 
779 	terminate_lease(&lease);
780 
781 	/* make sure the lease is gone */
782 	mrl.lessee_id = lease.lessee_id;
783 	igt_assert_eq(revoke_lease(data->master.fd, &mrl), -ENOENT);
784 }
785 
786 /* Test leasing objects more than once */
lease_again(data_t * data)787 static void lease_again(data_t *data)
788 {
789 	lease_t lease_a, lease_b;
790 
791 	/* Create a valid lease */
792 	igt_assert_eq(make_lease(data, &lease_a), 0);
793 
794 	/* Attempt to re-lease the same objects */
795 	igt_assert_eq(make_lease(data, &lease_b), -EBUSY);
796 
797 	terminate_lease(&lease_a);
798 
799 	/* Now attempt to lease the same objects */
800 	igt_assert_eq(make_lease(data, &lease_b), 0);
801 
802 	terminate_lease(&lease_b);
803 }
804 
805 #define assert_unleased(ret) \
806 	igt_assert_f((ret) == -EINVAL || (ret) == -ENOENT, \
807 		     "wrong return code %i, %s\n", ret, \
808 		     strerror(ret))
809 /* Test leasing an invalid connector */
lease_invalid_connector(data_t * data)810 static void lease_invalid_connector(data_t *data)
811 {
812 	lease_t lease;
813 	uint32_t save_connector_id;
814 	int ret;
815 
816 	/* Create an invalid lease */
817 	save_connector_id = data->connector_id;
818 	data->connector_id = 0xbaadf00d;
819 	ret = make_lease(data, &lease);
820 	data->connector_id = save_connector_id;
821 	assert_unleased(ret);
822 }
823 
824 /* Test leasing an invalid crtc */
lease_invalid_crtc(data_t * data)825 static void lease_invalid_crtc(data_t *data)
826 {
827 	lease_t lease;
828 	uint32_t save_crtc_id;
829 	int ret;
830 
831 	/* Create an invalid lease */
832 	save_crtc_id = data->crtc_id;
833 	data->crtc_id = 0xbaadf00d;
834 	ret = make_lease(data, &lease);
835 	data->crtc_id = save_crtc_id;
836 	assert_unleased(ret);
837 }
838 
lease_invalid_plane(data_t * data)839 static void lease_invalid_plane(data_t *data)
840 {
841 	lease_t lease;
842 	uint32_t save_plane_id;
843 	int ret;
844 
845 	/* Create an invalid lease */
846 	save_plane_id = data->plane_id;
847 	data->plane_id = 0xbaadf00d;
848 	ret = make_lease(data, &lease);
849 	data->plane_id = save_plane_id;
850 	assert_unleased(ret);
851 }
852 
853 
run_test(data_t * data,void (* testfunc)(data_t *))854 static void run_test(data_t *data, void (*testfunc)(data_t *))
855 {
856 	lease_t *master = &data->master;
857 	igt_display_t *display = &master->display;
858 	igt_output_t *output;
859 	enum pipe p;
860 	unsigned int valid_tests = 0;
861 
862 	for_each_pipe_with_valid_output(display, p, output) {
863 		igt_info("Beginning %s on pipe %s, connector %s\n",
864 			 igt_subtest_name(),
865 			 kmstest_pipe_name(p),
866 			 igt_output_name(output));
867 
868 		data->pipe = p;
869 		data->crtc_id = pipe_to_crtc_id(display, p);
870 		data->connector_id = output->id;
871 		data->plane_id =
872 			igt_pipe_get_plane_type(&data->master.display.pipes[data->pipe],
873 						DRM_PLANE_TYPE_PRIMARY)->drm_plane->plane_id;
874 
875 		testfunc(data);
876 
877 		igt_info("\n%s on pipe %s, connector %s: PASSED\n\n",
878 			 igt_subtest_name(),
879 			 kmstest_pipe_name(p),
880 			 igt_output_name(output));
881 
882 		valid_tests++;
883 	}
884 
885 	igt_require_f(valid_tests,
886 		      "no valid crtc/connector combinations found\n");
887 }
888 
889 #define assert_double_id_err(ret) \
890 	igt_assert_f((ret) == -EBUSY || (ret) == -ENOSPC, \
891 		     "wrong return code %i, %s\n", ret, \
892 		     strerror(ret))
invalid_create_leases(data_t * data)893 static void invalid_create_leases(data_t *data)
894 {
895 	uint32_t object_ids[4];
896 	struct local_drm_mode_create_lease mcl;
897 	drmModeRes *resources;
898 	int tmp_fd, ret;
899 
900 	/* empty lease */
901 	mcl.object_ids = 0;
902 	mcl.object_count = 0;
903 	mcl.flags = 0;
904 	igt_assert_eq(create_lease(data->master.fd, &mcl), -EINVAL);
905 
906 	/* NULL array pointer */
907 	mcl.object_count = 1;
908 	igt_assert_eq(create_lease(data->master.fd, &mcl), -EFAULT);
909 
910 	/* nil object */
911 	object_ids[0] = 0;
912 	mcl.object_ids = (uint64_t) (uintptr_t) object_ids;
913 	mcl.object_count = 1;
914 	igt_assert_eq(create_lease(data->master.fd, &mcl), -ENOENT);
915 
916 	/* no crtc, non-universal_plane */
917 	drmSetClientCap(data->master.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 0);
918 	object_ids[0] = data->master.display.outputs[0].id;
919 	igt_assert_eq(create_lease(data->master.fd, &mcl), -EINVAL);
920 
921 	/* no connector, non-universal_plane */
922 	object_ids[0] = data->master.display.pipes[0].crtc_id;
923 	igt_assert_eq(create_lease(data->master.fd, &mcl), -EINVAL);
924 
925 	/* sanity check */
926 	object_ids[0] = data->master.display.pipes[0].crtc_id;
927 	object_ids[1] = data->master.display.outputs[0].id;
928 	mcl.object_count = 2;
929 	igt_assert_eq(create_lease(data->master.fd, &mcl), 0);
930 	close(mcl.fd);
931 
932 	/* no plane, universal planes */
933 	drmSetClientCap(data->master.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
934 	igt_assert_eq(create_lease(data->master.fd, &mcl), -EINVAL);
935 
936 	/* sanity check */
937 	object_ids[2] = igt_pipe_get_plane_type(&data->master.display.pipes[0],
938 						DRM_PLANE_TYPE_PRIMARY)->drm_plane->plane_id;
939 	mcl.object_count = 3;
940 	igt_assert_eq(create_lease(data->master.fd, &mcl), 0);
941 	close(mcl.fd);
942 
943 	/* array overflow, do a small scan around overflow sizes */
944 	for (int i = 1; i <= 4; i++) {
945 		mcl.object_count = UINT32_MAX / sizeof(object_ids[0]) + i;
946 		igt_assert_eq(create_lease(data->master.fd, &mcl), -ENOMEM);
947 	}
948 
949 	/* sanity check */
950 	mcl.object_count = 3;
951 	mcl.flags = O_CLOEXEC | O_NONBLOCK;
952 	igt_assert_eq(create_lease(data->master.fd, &mcl), 0);
953 	close(mcl.fd);
954 
955 	/* invalid flags */
956 	mcl.flags = -1;
957 	igt_assert_eq(create_lease(data->master.fd, &mcl), -EINVAL);
958 
959 	/* no subleasing */
960 	mcl.object_count = 3;
961 	mcl.flags = 0;
962 	igt_assert_eq(create_lease(data->master.fd, &mcl), 0);
963 	tmp_fd = mcl.fd;
964 	igt_assert_eq(create_lease(tmp_fd, &mcl), -EINVAL);
965 	close(tmp_fd);
966 
967 	/* no double-leasing */
968 	igt_assert_eq(create_lease(data->master.fd, &mcl), 0);
969 	tmp_fd = mcl.fd;
970 	igt_assert_eq(create_lease(data->master.fd, &mcl), -EBUSY);
971 	close(tmp_fd);
972 
973 	/* no double leasing */
974 	object_ids[3] = object_ids[2];
975 	mcl.object_count = 4;
976 	/* Note: the ENOSPC is from idr double-insertion failing */
977 	ret = create_lease(data->master.fd, &mcl);
978 	assert_double_id_err(ret);
979 
980 	/* no encoder leasing */
981 	resources = drmModeGetResources(data->master.fd);
982 	igt_assert(resources);
983 	igt_assert(resources->count_encoders > 0);
984 	object_ids[3] = resources->encoders[0];
985 	igt_assert_eq(create_lease(data->master.fd, &mcl), -EINVAL);
986 	drmModeFreeResources(resources);
987 }
988 
check_crtc_masks(int master_fd,int lease_fd,uint32_t crtc_mask)989 static void check_crtc_masks(int master_fd, int lease_fd, uint32_t crtc_mask)
990 {
991 	drmModeRes *resources;
992 	drmModePlaneRes *plane_resources;
993 	int i;
994 
995 	resources = drmModeGetResources(master_fd);
996 	igt_assert(resources);
997 	plane_resources = drmModeGetPlaneResources(master_fd);
998 	igt_assert(plane_resources);
999 
1000 	for (i = 0; i < resources->count_encoders; i++) {
1001 		drmModeEncoder *master_e, *lease_e;
1002 		bool possible;
1003 
1004 		master_e = drmModeGetEncoder(master_fd, resources->encoders[i]);
1005 		igt_assert(master_e);
1006 		lease_e = drmModeGetEncoder(lease_fd, resources->encoders[i]);
1007 		igt_assert(lease_e);
1008 
1009 		possible = master_e->possible_crtcs & crtc_mask;
1010 
1011 		igt_assert_eq(lease_e->possible_crtcs,
1012 			      possible ? 1 : 0);
1013 		igt_assert_eq(master_e->possible_crtcs & crtc_mask,
1014 			      possible ? crtc_mask : 0);
1015 		drmModeFreeEncoder(master_e);
1016 		drmModeFreeEncoder(lease_e);
1017 	}
1018 
1019 	for (i = 0; i < plane_resources->count_planes; i++) {
1020 		drmModePlane *master_p, *lease_p;
1021 		bool possible;
1022 
1023 		master_p = drmModeGetPlane(master_fd, plane_resources->planes[i]);
1024 		igt_assert(master_p);
1025 		lease_p = drmModeGetPlane(lease_fd, plane_resources->planes[i]);
1026 		igt_assert(lease_p);
1027 
1028 		possible = master_p->possible_crtcs & crtc_mask;
1029 
1030 		igt_assert_eq(lease_p->possible_crtcs,
1031 			      possible ? 1 : 0);
1032 		igt_assert_eq(master_p->possible_crtcs & crtc_mask,
1033 			      possible ? crtc_mask : 0);
1034 		drmModeFreePlane(master_p);
1035 		drmModeFreePlane(lease_p);
1036 	}
1037 
1038 	drmModeFreePlaneResources(plane_resources);
1039 	drmModeFreeResources(resources);
1040 }
1041 
possible_crtcs_filtering(data_t * data)1042 static void possible_crtcs_filtering(data_t *data)
1043 {
1044 	uint32_t *object_ids;
1045 	struct local_drm_mode_create_lease mcl;
1046 	drmModeRes *resources;
1047 	drmModePlaneRes *plane_resources;
1048 	int i;
1049 	int master_fd = data->master.fd;
1050 
1051 	resources = drmModeGetResources(master_fd);
1052 	igt_assert(resources);
1053 	plane_resources = drmModeGetPlaneResources(master_fd);
1054 	igt_assert(plane_resources);
1055 	mcl.object_count = resources->count_connectors +
1056 		plane_resources->count_planes + 1;
1057 	object_ids = calloc(mcl.object_count, sizeof(*object_ids));
1058 	igt_assert(object_ids);
1059 
1060 	for (i = 0; i < resources->count_connectors; i++)
1061 		object_ids[i] = resources->connectors[i];
1062 
1063 	for (i = 0; i < plane_resources->count_planes; i++)
1064 		object_ids[i + resources->count_connectors] =
1065 			plane_resources->planes[i];
1066 
1067 	mcl.object_ids = (uint64_t) (uintptr_t) object_ids;
1068 	mcl.flags = 0;
1069 
1070 	for (i = 0; i < resources->count_crtcs; i++) {
1071 		int lease_fd;
1072 
1073 		object_ids[mcl.object_count - 1] =
1074 			resources->crtcs[i];
1075 
1076 		igt_assert_eq(create_lease(master_fd, &mcl), 0);
1077 		lease_fd = mcl.fd;
1078 
1079 		drmSetClientCap(lease_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
1080 
1081 		check_crtc_masks(master_fd, lease_fd, 1 << i);
1082 
1083 		close(lease_fd);
1084 	}
1085 
1086 	free(object_ids);
1087 	drmModeFreePlaneResources(plane_resources);
1088 	drmModeFreeResources(resources);
1089 }
1090 
is_master(int fd)1091 static bool is_master(int fd)
1092 {
1093 	/* FIXME: replace with drmIsMaster once we bumped libdrm version */
1094 	return drmAuthMagic(fd, 0) != -EACCES;
1095 }
1096 
_create_simple_lease(int master_fd,data_t * data,int expected_ret)1097 static int _create_simple_lease(int master_fd, data_t *data, int expected_ret)
1098 {
1099 	uint32_t object_ids[3];
1100 	struct local_drm_mode_create_lease mcl;
1101 
1102 	object_ids[0] = data->master.display.pipes[0].crtc_id;
1103 	object_ids[1] = data->master.display.outputs[0].id;
1104 	object_ids[2] = igt_pipe_get_plane_type(&data->master.display.pipes[0],
1105 						DRM_PLANE_TYPE_PRIMARY)->drm_plane->plane_id;
1106 	mcl.object_ids = (uint64_t) (uintptr_t) object_ids;
1107 	mcl.object_count = 3;
1108 	mcl.flags = 0;
1109 
1110 	igt_assert_eq(create_lease(master_fd, &mcl), expected_ret);
1111 
1112 	return expected_ret == 0 ? mcl.fd : 0;
1113 }
1114 
create_simple_lease(int master_fd,data_t * data)1115 static int create_simple_lease(int master_fd, data_t *data)
1116 {
1117 	return _create_simple_lease(master_fd, data, 0);
1118 }
1119 
1120 /* check lease master status in lockdep with lessors, but can't change it
1121  * themselves */
master_vs_lease(data_t * data)1122 static void master_vs_lease(data_t *data)
1123 {
1124 	int lease_fd;
1125 
1126 	lease_fd = create_simple_lease(data->master.fd, data);
1127 
1128 	igt_assert_eq(drmDropMaster(lease_fd), -1);
1129 	igt_assert_eq(errno, EINVAL);
1130 
1131 	igt_assert(is_master(data->master.fd));
1132 	igt_assert(is_master(lease_fd));
1133 
1134 	igt_device_drop_master(data->master.fd);
1135 
1136 	igt_assert(!is_master(data->master.fd));
1137 	igt_assert(!is_master(lease_fd));
1138 
1139 	igt_assert_eq(drmSetMaster(lease_fd), -1);
1140 	igt_assert_eq(errno, EINVAL);
1141 
1142 	igt_device_set_master(data->master.fd);
1143 
1144 	igt_assert(is_master(data->master.fd));
1145 	igt_assert(is_master(lease_fd));
1146 
1147 	close(lease_fd);
1148 }
1149 
multimaster_lease(data_t * data)1150 static void multimaster_lease(data_t *data)
1151 {
1152 	int lease_fd, master2_fd, lease2_fd;
1153 
1154 	lease_fd = create_simple_lease(data->master.fd, data);
1155 
1156 	igt_assert(is_master(data->master.fd));
1157 	igt_assert(is_master(lease_fd));
1158 
1159 	master2_fd = drm_open_driver(DRIVER_ANY);
1160 
1161 	igt_assert(!is_master(master2_fd));
1162 
1163 	_create_simple_lease(master2_fd, data, -EACCES);
1164 
1165 	igt_device_drop_master(data->master.fd);
1166 	igt_device_set_master(master2_fd);
1167 
1168 	igt_assert(!is_master(data->master.fd));
1169 	igt_assert(!is_master(lease_fd));
1170 	igt_assert(is_master(master2_fd));
1171 
1172 	drmSetClientCap(master2_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
1173 	lease2_fd = create_simple_lease(master2_fd, data);
1174 
1175 	close(master2_fd); /* close is an implicit DropMaster */
1176 	igt_assert(!is_master(lease2_fd));
1177 
1178 	igt_device_set_master(data->master.fd);
1179 	igt_assert(is_master(data->master.fd));
1180 	igt_assert(is_master(lease_fd));
1181 
1182 	close(lease2_fd);
1183 	close(lease_fd);
1184 }
1185 
implicit_plane_lease(data_t * data)1186 static void implicit_plane_lease(data_t *data)
1187 {
1188 	uint32_t object_ids[3];
1189 	struct local_drm_mode_create_lease mcl;
1190 	struct local_drm_mode_get_lease mgl;
1191 	int ret;
1192 	uint32_t cursor_id = igt_pipe_get_plane_type(&data->master.display.pipes[0],
1193 						     DRM_PLANE_TYPE_CURSOR)->drm_plane->plane_id;
1194 
1195 	object_ids[0] = data->master.display.pipes[0].crtc_id;
1196 	object_ids[1] = data->master.display.outputs[0].id;
1197 	object_ids[2] = igt_pipe_get_plane_type(&data->master.display.pipes[0],
1198 						DRM_PLANE_TYPE_PRIMARY)->drm_plane->plane_id;
1199 	mcl.object_ids = (uint64_t) (uintptr_t) object_ids;
1200 	mcl.object_count = 3;
1201 	mcl.flags = 0;
1202 
1203 	/* sanity check */
1204 	igt_assert_eq(create_lease(data->master.fd, &mcl), 0);
1205 	close(mcl.fd);
1206 	drmSetClientCap(data->master.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 0);
1207 
1208 	/* non universal plane automatically adds primary/cursor plane */
1209 	mcl.object_count = 2;
1210 	igt_assert_eq(create_lease(data->master.fd, &mcl), 0);
1211 
1212 	mgl.pad = 0;
1213 	mgl.count_objects = 0;
1214 	mgl.objects_ptr = 0;
1215 	igt_assert_eq(get_lease(mcl.fd, &mgl), 0);
1216 
1217 	igt_assert_eq(mgl.count_objects, 3 + (cursor_id ? 1 : 0));
1218 
1219 	close(mcl.fd);
1220 
1221 	/* check that implicit lease doesn't lead to confusion when
1222 	 * explicitly adding primary plane */
1223 	mcl.object_count = 3;
1224 	ret = create_lease(data->master.fd, &mcl);
1225 	assert_double_id_err(ret);
1226 
1227 	/* same for the cursor */
1228 	object_ids[2] = cursor_id;
1229 	ret = create_lease(data->master.fd, &mcl);
1230 	assert_double_id_err(ret);
1231 
1232 	drmSetClientCap(data->master.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
1233 }
1234 
lease_uevent(data_t * data)1235 static void lease_uevent(data_t *data)
1236 {
1237 	int lease_fd;
1238 	struct local_drm_mode_list_lessees mll;
1239 	struct udev_monitor *uevent_monitor;
1240 
1241 	uevent_monitor = igt_watch_hotplug();
1242 
1243 	igt_flush_hotplugs(uevent_monitor);
1244 
1245 	lease_fd = create_simple_lease(data->master.fd, data);
1246 
1247 	igt_assert(!igt_lease_change_detected(uevent_monitor, 1));
1248 
1249 	mll.pad = 0;
1250 	mll.count_lessees = 0;
1251 	mll.lessees_ptr = 0;
1252 	igt_assert_eq(list_lessees(data->master.fd, &mll), 0);
1253 	igt_assert_eq(mll.count_lessees, 1);
1254 
1255 	close(lease_fd);
1256 
1257 	igt_assert(igt_lease_change_detected(uevent_monitor, 1));
1258 
1259 	mll.lessees_ptr = 0;
1260 	igt_assert_eq(list_lessees(data->master.fd, &mll), 0);
1261 	igt_assert_eq(mll.count_lessees, 0);
1262 
1263 	igt_cleanup_hotplug(uevent_monitor);
1264 }
1265 
1266 igt_main
1267 {
1268 	data_t data;
1269 	const struct {
1270 		const char *name;
1271 		void (*func)(data_t *);
1272 	} funcs[] = {
1273 		{ "simple_lease", simple_lease },
1274 		{ "lessee_list", lessee_list },
1275 		{ "lease_get", lease_get },
1276 		{ "lease_unleased_connector", lease_unleased_connector },
1277 		{ "lease_unleased_crtc", lease_unleased_crtc },
1278 		{ "lease_revoke", lease_revoke },
1279 		{ "lease_again", lease_again },
1280 		{ "lease_invalid_connector", lease_invalid_connector },
1281 		{ "lease_invalid_crtc", lease_invalid_crtc },
1282 		{ "lease_invalid_plane", lease_invalid_plane },
1283 		{ "page_flip_implicit_plane", page_flip_implicit_plane },
1284 		{ "setcrtc_implicit_plane", setcrtc_implicit_plane },
1285 		{ "cursor_implicit_plane", cursor_implicit_plane },
1286 		{ "atomic_implicit_crtc", atomic_implicit_crtc },
1287 		{ }
1288 	}, *f;
1289 
1290 	igt_fixture {
1291 		data.master.fd = drm_open_driver_master(DRIVER_ANY);
1292 		kmstest_set_vt_graphics_mode();
1293 		igt_display_require(&data.master.display, data.master.fd);
1294 	}
1295 
1296 	for (f = funcs; f->name; f++) {
1297 
1298 		igt_subtest_f("%s", f->name) {
1299 			run_test(&data, f->func);
1300 		}
1301 	}
1302 
1303 	igt_subtest("invalid-create-leases")
1304 		invalid_create_leases(&data);
1305 
1306 	igt_subtest("possible-crtcs-filtering")
1307 		possible_crtcs_filtering(&data);
1308 
1309 	igt_subtest("master-vs-lease")
1310 		master_vs_lease(&data);
1311 
1312 	igt_subtest("multimaster-lease")
1313 		multimaster_lease(&data);
1314 
1315 	igt_subtest("implicit-plane-lease")
1316 		implicit_plane_lease(&data);
1317 
1318 	igt_subtest("lease-uevent")
1319 		lease_uevent(&data);
1320 }
1321