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