Message ID | 20171001035234.24891-1-keithp@keithp.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 1 October 2017 at 13:52, <keithp@keithp.com> wrote: > From: Keith Packard <keithp@keithp.com> > > Validate that the leasing API creates leases that allow access to a > subset of the available resources and that lease revocation works. These don't test the GET and LIST_LEASES interfaces At least some basic test coverage for those would be good. Dave. > > Signed-off-by: Keith Packard <keithp@keithp.com> > --- > tests/Makefile.sources | 1 + > tests/kms_lease.c | 439 +++++++++++++++++++++++++++++++++++++++++++++++++ > tests/meson.build | 1 + > 3 files changed, 441 insertions(+) > create mode 100644 tests/kms_lease.c > > diff --git a/tests/Makefile.sources b/tests/Makefile.sources > index 19e8ae3f..ede77c7d 100644 > --- a/tests/Makefile.sources > +++ b/tests/Makefile.sources > @@ -192,6 +192,7 @@ TESTS_progs = \ > kms_frontbuffer_tracking \ > kms_hdmi_inject \ > kms_invalid_dotclock \ > + kms_lease \ > kms_legacy_colorkey \ > kms_mmap_write_crc \ > kms_mmio_vs_cs_flip \ > diff --git a/tests/kms_lease.c b/tests/kms_lease.c > new file mode 100644 > index 00000000..eed836de > --- /dev/null > +++ b/tests/kms_lease.c > @@ -0,0 +1,439 @@ > +/* > + * Copyright © 2017 Keith Packard > + * > + * Permission is hereby granted, free of charge, to any person obtaining a > + * copy of this software and associated documentation files (the "Software"), > + * to deal in the Software without restriction, including without limitation > + * the rights to use, copy, modify, merge, publish, distribute, sublicense, > + * and/or sell copies of the Software, and to permit persons to whom the > + * Software is furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice (including the next > + * paragraph) shall be included in all copies or substantial portions of the > + * Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS > + * IN THE SOFTWARE. > + */ > + > +/** @file kms_lease.c > + * > + * This is a test of DRM leases > + */ > + > + > +#include "igt.h" > +#include <stdlib.h> > +#include <stdio.h> > +#include <string.h> > +#include <fcntl.h> > +#include <inttypes.h> > +#include <errno.h> > +#include <time.h> > +#include <sys/poll.h> > +#include <sys/stat.h> > +#include <sys/time.h> > +#include <sys/wait.h> > + > +#include <drm.h> > + > +IGT_TEST_DESCRIPTION("Test of CreateLease."); > + > +typedef struct { > + int fd; > + uint32_t lessee_id; > + igt_display_t display; > + struct igt_fb primary_fb; > + igt_output_t *output; > + drmModeModeInfo *mode; > +} lease_t; > + > +typedef struct { > + lease_t master; > + enum pipe pipe; > + uint32_t crtc_id; > + uint32_t connector_id; > +} data_t; > + > +static uint32_t pipe_to_crtc_id(igt_display_t *display, enum pipe pipe) > +{ > + return display->pipes[pipe].crtc_id; > +} > + > +static enum pipe crtc_id_to_pipe(igt_display_t *display, uint32_t crtc_id) > +{ > + enum pipe pipe; > + > + for (pipe = 0; pipe < display->n_pipes; pipe++) > + if (display->pipes[pipe].crtc_id == crtc_id) > + return pipe; > + return -1; > +} > + > +static igt_output_t *connector_id_to_output(igt_display_t *display, uint32_t connector_id) > +{ > + drmModeConnector connector; > + > + connector.connector_id = connector_id; > + return igt_output_from_connector(display, &connector); > +} > + > +static int prepare_crtc(lease_t *lease, uint32_t connector_id, uint32_t crtc_id) > +{ > + drmModeModeInfo *mode; > + igt_display_t *display = &lease->display; > + igt_output_t *output = connector_id_to_output(display, connector_id); > + enum pipe pipe = crtc_id_to_pipe(display, crtc_id); > + igt_plane_t *primary; > + int ret; > + > + if (!output) > + return -ENOENT; > + > + /* select the pipe we want to use */ > + igt_output_set_pipe(output, pipe); > + > + /* create and set the primary plane fb */ > + mode = igt_output_get_mode(output); > + igt_create_color_fb(lease->fd, mode->hdisplay, mode->vdisplay, > + DRM_FORMAT_XRGB8888, > + LOCAL_DRM_FORMAT_MOD_NONE, > + 0.0, 0.0, 0.0, > + &lease->primary_fb); > + > + /* Check to see if the crtc selected is valid */ > + if (!igt_output_get_driving_pipe(output)) > + return -ENOENT; > + > + primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY); > + igt_plane_set_fb(primary, &lease->primary_fb); > + > + ret = igt_display_try_commit2(display, COMMIT_LEGACY); > + > + if (ret) > + return ret; > + > + igt_wait_for_vblank(lease->fd, pipe); > + > + lease->output = output; > + lease->mode = mode; > + return 0; > +} > + > +static void cleanup_crtc(lease_t *lease, igt_output_t *output) > +{ > + igt_display_t *display = &lease->display; > + igt_plane_t *primary; > + > + igt_remove_fb(lease->fd, &lease->primary_fb); > + > + primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY); > + igt_plane_set_fb(primary, NULL); > + > + igt_output_set_pipe(output, PIPE_ANY); > + igt_display_commit(display); > +} > + > +static int create_lease(int fd, struct drm_mode_create_lease *mcl) > +{ > + int err = 0; > + > + if (igt_ioctl(fd, DRM_IOCTL_MODE_CREATE_LEASE, mcl)) > + err = -errno; > + return err; > +} > + > +static int revoke_lease(int fd, struct drm_mode_revoke_lease *mrl) > +{ > + int err = 0; > + > + if (igt_ioctl(fd, DRM_IOCTL_MODE_REVOKE_LEASE, mrl)) > + err = -errno; > + return err; > +} > + > +static int make_lease(data_t *data, lease_t *lease) > +{ > + uint32_t object_ids[3]; > + struct drm_mode_create_lease mcl; > + int ret; > + > + mcl.object_ids = (uint64_t) (uintptr_t) &object_ids[0]; > + mcl.object_count = 0; > + mcl.flags = 0; > + > + object_ids[mcl.object_count++] = data->connector_id; > + object_ids[mcl.object_count++] = data->crtc_id; > + > + ret = create_lease(data->master.fd, &mcl); > + > + if (ret) > + return ret; > + > + lease->fd = mcl.fd; > + lease->lessee_id = mcl.lessee_id; > + return 0; > +} > + > +static void terminate_lease(lease_t *lease) > +{ > + close(lease->fd); > +} > + > +static int 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) > +{ > + cairo_t *cr; > + > + cr = igt_get_cairo_ctx(drm_fd, fb); > + > + igt_paint_color_gradient(cr, 0, 0, fb->width, fb->height, 1, 1, 1); > + igt_paint_test_pattern(cr, fb->width, fb->height); > + > + cairo_move_to(cr, fb->width / 2, fb->height / 2); > + cairo_set_font_size(cr, 36); > + igt_cairo_printf_line(cr, align_hcenter, 10, "%s", test_name); > + igt_cairo_printf_line(cr, align_hcenter, 10, "%s", mode_format_str); > + igt_cairo_printf_line(cr, align_hcenter, 10, "%s", connector_str); > + igt_cairo_printf_line(cr, align_hcenter, 10, "%s", pipe_str); > + > + cairo_destroy(cr); > + > + return 0; > +} > + > +static void simple_lease(data_t *data) > +{ > + lease_t lease; > + > + /* Create a valid lease */ > + igt_assert_eq(make_lease(data, &lease), 0); > + > + igt_display_init(&lease.display, lease.fd); > + > + /* Set a mode on the leased output */ > + igt_assert_eq(0, prepare_crtc(&lease, data->connector_id, data->crtc_id)); > + > + /* Paint something attractive */ > + paint_fb(lease.fd, &lease.primary_fb, "simple_lease", > + lease.mode->name, igt_output_name(lease.output), kmstest_pipe_name(data->pipe)); > + sleep(3); > + cleanup_crtc(&lease, > + connector_id_to_output(&lease.display, data->connector_id)); > + > + terminate_lease(&lease); > +} > + > +static void lease_unleased_crtc(data_t *data) > +{ > + lease_t lease; > + enum pipe p; > + uint32_t bad_crtc_id; > + int ret; > + > + /* Create a valid lease */ > + igt_assert_eq(make_lease(data, &lease), 0); > + > + igt_display_init(&lease.display, lease.fd); > + > + /* Find another CRTC that we don't control */ > + bad_crtc_id = 0; > + for (p = 0; bad_crtc_id == 0 && p < data->master.display.n_pipes; p++) { > + if (pipe_to_crtc_id(&data->master.display, p) != data->crtc_id) > + bad_crtc_id = pipe_to_crtc_id(&data->master.display, p); > + } > + > + /* Give up if there isn't another crtc */ > + igt_skip_on(bad_crtc_id == 0); > + > + /* Attempt to use the unleased crtc id. Note that the > + * failure here is not directly from the kernel because the > + * resources returned from the kernel will not contain this resource > + * id and hence the igt helper functions will fail to find it > + */ > + ret = prepare_crtc(&lease, data->connector_id, bad_crtc_id); > + > + /* Ensure the expected error is returned */ > + igt_assert_eq(ret, -ENOENT); > + > + terminate_lease(&lease); > +} > + > +static void lease_unleased_connector(data_t *data) > +{ > + lease_t lease; > + int o; > + uint32_t bad_connector_id; > + int ret; > + > + /* Create a valid lease */ > + igt_assert_eq(make_lease(data, &lease), 0); > + > + igt_display_init(&lease.display, lease.fd); > + > + /* Find another connector that we don't control */ > + bad_connector_id = 0; > + for (o = 0; bad_connector_id == 0 && o < data->master.display.n_outputs; o++) { > + if (data->master.display.outputs[o].id != data->connector_id) > + bad_connector_id = data->master.display.outputs[o].id; > + } > + > + /* Give up if there isn't another connector */ > + igt_skip_on(bad_connector_id == 0); > + > + /* Attempt to use the unleased connector id. Note that the > + * failure here is not directly from the kernel because the > + * resources returned from the kernel will not contain this resource > + * id and hence the igt helper functions will fail to find it > + */ > + ret = prepare_crtc(&lease, bad_connector_id, data->crtc_id); > + > + /* Ensure the expected error is returned */ > + igt_assert_eq(ret, -ENOENT); > + > + terminate_lease(&lease); > +} > + > +/* Test revocation of lease */ > +static void lease_revoke(data_t *data) > +{ > + lease_t lease; > + struct drm_mode_revoke_lease mrl; > + int ret; > + > + /* Create a valid lease */ > + igt_assert_eq(make_lease(data, &lease), 0); > + > + igt_display_init(&lease.display, lease.fd); > + > + /* Revoke the lease using the master fd */ > + mrl.lessee_id = lease.lessee_id; > + igt_assert_eq(revoke_lease(data->master.fd, &mrl), 0); > + > + /* Try to use the leased objects */ > + ret = prepare_crtc(&lease, data->connector_id, data->crtc_id); > + > + /* Ensure that the expected error is returned */ > + igt_assert_eq(ret, -ENOENT); > + > + terminate_lease(&lease); > +} > + > +/* Test leasing objects more than once */ > +static void lease_again(data_t *data) > +{ > + lease_t lease_a, lease_b; > + > + /* Create a valid lease */ > + igt_assert_eq(make_lease(data, &lease_a), 0); > + > + /* Attempt to re-lease the same objects */ > + igt_assert_eq(make_lease(data, &lease_b), -EBUSY); > + > + terminate_lease(&lease_a); > + > + /* Now attempt to lease the same objects */ > + igt_assert_eq(make_lease(data, &lease_b), 0); > + > + terminate_lease(&lease_b); > +} > + > +/* Test leasing an invalid connector */ > +static void lease_invalid_connector(data_t *data) > +{ > + lease_t lease; > + uint32_t save_connector_id; > + int ret; > + > + /* Create an invalid lease */ > + save_connector_id = data->connector_id; > + data->connector_id = 0xbaadf00d; > + ret = make_lease(data, &lease); > + data->connector_id = save_connector_id; > + igt_assert_eq(ret, -EINVAL); > +} > + > +/* Test leasing an invalid crtc */ > +static void lease_invalid_crtc(data_t *data) > +{ > + lease_t lease; > + uint32_t save_crtc_id; > + int ret; > + > + /* Create an invalid lease */ > + save_crtc_id = data->crtc_id; > + data->crtc_id = 0xbaadf00d; > + ret = make_lease(data, &lease); > + data->crtc_id = save_crtc_id; > + igt_assert_eq(ret, -EINVAL); > +} > + > +static void run_test(data_t *data, void (*testfunc)(data_t *)) > +{ > + lease_t *master = &data->master; > + igt_display_t *display = &master->display; > + igt_output_t *output; > + enum pipe p; > + unsigned int valid_tests = 0; > + > + for_each_pipe_with_valid_output(display, p, output) { > + igt_info("Beginning %s on pipe %s, connector %s\n", > + igt_subtest_name(), > + kmstest_pipe_name(p), > + igt_output_name(output)); > + > + data->pipe = p; > + data->crtc_id = pipe_to_crtc_id(display, p); > + data->connector_id = output->id; > + > + testfunc(data); > + > + igt_info("\n%s on pipe %s, connector %s: PASSED\n\n", > + igt_subtest_name(), > + kmstest_pipe_name(p), > + igt_output_name(output)); > + > + valid_tests++; > + } > + > + igt_require_f(valid_tests, > + "no valid crtc/connector combinations found\n"); > +} > + > +igt_main > +{ > + data_t data; > + const struct { > + const char *name; > + void (*func)(data_t *); > + } funcs[] = { > + { "simple_lease", simple_lease }, > + { "lease_unleased_connector", lease_unleased_connector }, > + { "lease_unleased_crtc", lease_unleased_crtc }, > + { "lease_revoke", lease_revoke }, > + { "lease_again", lease_again }, > + { "lease_invalid_connector", lease_invalid_connector }, > + { "lease_invalid_crtc", lease_invalid_crtc }, > + { } > + }, *f; > + > + igt_skip_on_simulation(); > + > + igt_fixture { > + data.master.fd = drm_open_driver(DRIVER_ANY); > + kmstest_set_vt_graphics_mode(); > + igt_display_init(&data.master.display, data.master.fd); > + } > + > + for (f = funcs; f->name; f++) { > + > + igt_subtest_f("%s", f->name) { > + run_test(&data, f->func); > + } > + } > +} > diff --git a/tests/meson.build b/tests/meson.build > index 6db92788..ac8dce97 100644 > --- a/tests/meson.build > +++ b/tests/meson.build > @@ -172,6 +172,7 @@ test_progs = [ > 'kms_frontbuffer_tracking', > 'kms_hdmi_inject', > 'kms_invalid_dotclock', > + 'kms_lease', > 'kms_legacy_colorkey', > 'kms_mmap_write_crc', > 'kms_mmio_vs_cs_flip', > -- > 2.14.1 > > _______________________________________________ > Intel-gfx mailing list > Intel-gfx@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
On 10 October 2017 at 16:57, Dave Airlie <airlied@gmail.com> wrote: > On 1 October 2017 at 13:52, <keithp@keithp.com> wrote: >> From: Keith Packard <keithp@keithp.com> >> >> Validate that the leasing API creates leases that allow access to a >> subset of the available resources and that lease revocation works. > > These don't test the GET and LIST_LEASES interfaces > > At least some basic test coverage for those would be good. This also probably needs the local treatment, though we have to renumber the ioctls from your lease kernel patches. Also subject should be tests/kms_lease: Dave.
diff --git a/tests/Makefile.sources b/tests/Makefile.sources index 19e8ae3f..ede77c7d 100644 --- a/tests/Makefile.sources +++ b/tests/Makefile.sources @@ -192,6 +192,7 @@ TESTS_progs = \ kms_frontbuffer_tracking \ kms_hdmi_inject \ kms_invalid_dotclock \ + kms_lease \ kms_legacy_colorkey \ kms_mmap_write_crc \ kms_mmio_vs_cs_flip \ diff --git a/tests/kms_lease.c b/tests/kms_lease.c new file mode 100644 index 00000000..eed836de --- /dev/null +++ b/tests/kms_lease.c @@ -0,0 +1,439 @@ +/* + * Copyright © 2017 Keith Packard + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/** @file kms_lease.c + * + * This is a test of DRM leases + */ + + +#include "igt.h" +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <time.h> +#include <sys/poll.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/wait.h> + +#include <drm.h> + +IGT_TEST_DESCRIPTION("Test of CreateLease."); + +typedef struct { + int fd; + uint32_t lessee_id; + igt_display_t display; + struct igt_fb primary_fb; + igt_output_t *output; + drmModeModeInfo *mode; +} lease_t; + +typedef struct { + lease_t master; + enum pipe pipe; + uint32_t crtc_id; + uint32_t connector_id; +} data_t; + +static uint32_t pipe_to_crtc_id(igt_display_t *display, enum pipe pipe) +{ + return display->pipes[pipe].crtc_id; +} + +static enum pipe crtc_id_to_pipe(igt_display_t *display, uint32_t crtc_id) +{ + enum pipe pipe; + + for (pipe = 0; pipe < display->n_pipes; pipe++) + if (display->pipes[pipe].crtc_id == crtc_id) + return pipe; + return -1; +} + +static igt_output_t *connector_id_to_output(igt_display_t *display, uint32_t connector_id) +{ + drmModeConnector connector; + + connector.connector_id = connector_id; + return igt_output_from_connector(display, &connector); +} + +static int prepare_crtc(lease_t *lease, uint32_t connector_id, uint32_t crtc_id) +{ + drmModeModeInfo *mode; + igt_display_t *display = &lease->display; + igt_output_t *output = connector_id_to_output(display, connector_id); + enum pipe pipe = crtc_id_to_pipe(display, crtc_id); + igt_plane_t *primary; + int ret; + + if (!output) + return -ENOENT; + + /* select the pipe we want to use */ + igt_output_set_pipe(output, pipe); + + /* create and set the primary plane fb */ + mode = igt_output_get_mode(output); + igt_create_color_fb(lease->fd, mode->hdisplay, mode->vdisplay, + DRM_FORMAT_XRGB8888, + LOCAL_DRM_FORMAT_MOD_NONE, + 0.0, 0.0, 0.0, + &lease->primary_fb); + + /* Check to see if the crtc selected is valid */ + if (!igt_output_get_driving_pipe(output)) + return -ENOENT; + + primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY); + igt_plane_set_fb(primary, &lease->primary_fb); + + ret = igt_display_try_commit2(display, COMMIT_LEGACY); + + if (ret) + return ret; + + igt_wait_for_vblank(lease->fd, pipe); + + lease->output = output; + lease->mode = mode; + return 0; +} + +static void cleanup_crtc(lease_t *lease, igt_output_t *output) +{ + igt_display_t *display = &lease->display; + igt_plane_t *primary; + + igt_remove_fb(lease->fd, &lease->primary_fb); + + primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY); + igt_plane_set_fb(primary, NULL); + + igt_output_set_pipe(output, PIPE_ANY); + igt_display_commit(display); +} + +static int create_lease(int fd, struct drm_mode_create_lease *mcl) +{ + int err = 0; + + if (igt_ioctl(fd, DRM_IOCTL_MODE_CREATE_LEASE, mcl)) + err = -errno; + return err; +} + +static int revoke_lease(int fd, struct drm_mode_revoke_lease *mrl) +{ + int err = 0; + + if (igt_ioctl(fd, DRM_IOCTL_MODE_REVOKE_LEASE, mrl)) + err = -errno; + return err; +} + +static int make_lease(data_t *data, lease_t *lease) +{ + uint32_t object_ids[3]; + struct drm_mode_create_lease mcl; + int ret; + + mcl.object_ids = (uint64_t) (uintptr_t) &object_ids[0]; + mcl.object_count = 0; + mcl.flags = 0; + + object_ids[mcl.object_count++] = data->connector_id; + object_ids[mcl.object_count++] = data->crtc_id; + + ret = create_lease(data->master.fd, &mcl); + + if (ret) + return ret; + + lease->fd = mcl.fd; + lease->lessee_id = mcl.lessee_id; + return 0; +} + +static void terminate_lease(lease_t *lease) +{ + close(lease->fd); +} + +static int 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) +{ + cairo_t *cr; + + cr = igt_get_cairo_ctx(drm_fd, fb); + + igt_paint_color_gradient(cr, 0, 0, fb->width, fb->height, 1, 1, 1); + igt_paint_test_pattern(cr, fb->width, fb->height); + + cairo_move_to(cr, fb->width / 2, fb->height / 2); + cairo_set_font_size(cr, 36); + igt_cairo_printf_line(cr, align_hcenter, 10, "%s", test_name); + igt_cairo_printf_line(cr, align_hcenter, 10, "%s", mode_format_str); + igt_cairo_printf_line(cr, align_hcenter, 10, "%s", connector_str); + igt_cairo_printf_line(cr, align_hcenter, 10, "%s", pipe_str); + + cairo_destroy(cr); + + return 0; +} + +static void simple_lease(data_t *data) +{ + lease_t lease; + + /* Create a valid lease */ + igt_assert_eq(make_lease(data, &lease), 0); + + igt_display_init(&lease.display, lease.fd); + + /* Set a mode on the leased output */ + igt_assert_eq(0, prepare_crtc(&lease, data->connector_id, data->crtc_id)); + + /* Paint something attractive */ + paint_fb(lease.fd, &lease.primary_fb, "simple_lease", + lease.mode->name, igt_output_name(lease.output), kmstest_pipe_name(data->pipe)); + sleep(3); + cleanup_crtc(&lease, + connector_id_to_output(&lease.display, data->connector_id)); + + terminate_lease(&lease); +} + +static void lease_unleased_crtc(data_t *data) +{ + lease_t lease; + enum pipe p; + uint32_t bad_crtc_id; + int ret; + + /* Create a valid lease */ + igt_assert_eq(make_lease(data, &lease), 0); + + igt_display_init(&lease.display, lease.fd); + + /* Find another CRTC that we don't control */ + bad_crtc_id = 0; + for (p = 0; bad_crtc_id == 0 && p < data->master.display.n_pipes; p++) { + if (pipe_to_crtc_id(&data->master.display, p) != data->crtc_id) + bad_crtc_id = pipe_to_crtc_id(&data->master.display, p); + } + + /* Give up if there isn't another crtc */ + igt_skip_on(bad_crtc_id == 0); + + /* Attempt to use the unleased crtc id. Note that the + * failure here is not directly from the kernel because the + * resources returned from the kernel will not contain this resource + * id and hence the igt helper functions will fail to find it + */ + ret = prepare_crtc(&lease, data->connector_id, bad_crtc_id); + + /* Ensure the expected error is returned */ + igt_assert_eq(ret, -ENOENT); + + terminate_lease(&lease); +} + +static void lease_unleased_connector(data_t *data) +{ + lease_t lease; + int o; + uint32_t bad_connector_id; + int ret; + + /* Create a valid lease */ + igt_assert_eq(make_lease(data, &lease), 0); + + igt_display_init(&lease.display, lease.fd); + + /* Find another connector that we don't control */ + bad_connector_id = 0; + for (o = 0; bad_connector_id == 0 && o < data->master.display.n_outputs; o++) { + if (data->master.display.outputs[o].id != data->connector_id) + bad_connector_id = data->master.display.outputs[o].id; + } + + /* Give up if there isn't another connector */ + igt_skip_on(bad_connector_id == 0); + + /* Attempt to use the unleased connector id. Note that the + * failure here is not directly from the kernel because the + * resources returned from the kernel will not contain this resource + * id and hence the igt helper functions will fail to find it + */ + ret = prepare_crtc(&lease, bad_connector_id, data->crtc_id); + + /* Ensure the expected error is returned */ + igt_assert_eq(ret, -ENOENT); + + terminate_lease(&lease); +} + +/* Test revocation of lease */ +static void lease_revoke(data_t *data) +{ + lease_t lease; + struct drm_mode_revoke_lease mrl; + int ret; + + /* Create a valid lease */ + igt_assert_eq(make_lease(data, &lease), 0); + + igt_display_init(&lease.display, lease.fd); + + /* Revoke the lease using the master fd */ + mrl.lessee_id = lease.lessee_id; + igt_assert_eq(revoke_lease(data->master.fd, &mrl), 0); + + /* Try to use the leased objects */ + ret = prepare_crtc(&lease, data->connector_id, data->crtc_id); + + /* Ensure that the expected error is returned */ + igt_assert_eq(ret, -ENOENT); + + terminate_lease(&lease); +} + +/* Test leasing objects more than once */ +static void lease_again(data_t *data) +{ + lease_t lease_a, lease_b; + + /* Create a valid lease */ + igt_assert_eq(make_lease(data, &lease_a), 0); + + /* Attempt to re-lease the same objects */ + igt_assert_eq(make_lease(data, &lease_b), -EBUSY); + + terminate_lease(&lease_a); + + /* Now attempt to lease the same objects */ + igt_assert_eq(make_lease(data, &lease_b), 0); + + terminate_lease(&lease_b); +} + +/* Test leasing an invalid connector */ +static void lease_invalid_connector(data_t *data) +{ + lease_t lease; + uint32_t save_connector_id; + int ret; + + /* Create an invalid lease */ + save_connector_id = data->connector_id; + data->connector_id = 0xbaadf00d; + ret = make_lease(data, &lease); + data->connector_id = save_connector_id; + igt_assert_eq(ret, -EINVAL); +} + +/* Test leasing an invalid crtc */ +static void lease_invalid_crtc(data_t *data) +{ + lease_t lease; + uint32_t save_crtc_id; + int ret; + + /* Create an invalid lease */ + save_crtc_id = data->crtc_id; + data->crtc_id = 0xbaadf00d; + ret = make_lease(data, &lease); + data->crtc_id = save_crtc_id; + igt_assert_eq(ret, -EINVAL); +} + +static void run_test(data_t *data, void (*testfunc)(data_t *)) +{ + lease_t *master = &data->master; + igt_display_t *display = &master->display; + igt_output_t *output; + enum pipe p; + unsigned int valid_tests = 0; + + for_each_pipe_with_valid_output(display, p, output) { + igt_info("Beginning %s on pipe %s, connector %s\n", + igt_subtest_name(), + kmstest_pipe_name(p), + igt_output_name(output)); + + data->pipe = p; + data->crtc_id = pipe_to_crtc_id(display, p); + data->connector_id = output->id; + + testfunc(data); + + igt_info("\n%s on pipe %s, connector %s: PASSED\n\n", + igt_subtest_name(), + kmstest_pipe_name(p), + igt_output_name(output)); + + valid_tests++; + } + + igt_require_f(valid_tests, + "no valid crtc/connector combinations found\n"); +} + +igt_main +{ + data_t data; + const struct { + const char *name; + void (*func)(data_t *); + } funcs[] = { + { "simple_lease", simple_lease }, + { "lease_unleased_connector", lease_unleased_connector }, + { "lease_unleased_crtc", lease_unleased_crtc }, + { "lease_revoke", lease_revoke }, + { "lease_again", lease_again }, + { "lease_invalid_connector", lease_invalid_connector }, + { "lease_invalid_crtc", lease_invalid_crtc }, + { } + }, *f; + + igt_skip_on_simulation(); + + igt_fixture { + data.master.fd = drm_open_driver(DRIVER_ANY); + kmstest_set_vt_graphics_mode(); + igt_display_init(&data.master.display, data.master.fd); + } + + for (f = funcs; f->name; f++) { + + igt_subtest_f("%s", f->name) { + run_test(&data, f->func); + } + } +} diff --git a/tests/meson.build b/tests/meson.build index 6db92788..ac8dce97 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -172,6 +172,7 @@ test_progs = [ 'kms_frontbuffer_tracking', 'kms_hdmi_inject', 'kms_invalid_dotclock', + 'kms_lease', 'kms_legacy_colorkey', 'kms_mmap_write_crc', 'kms_mmio_vs_cs_flip',