1 /* Copyright 2020-2021 IGEL Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
21 #include <xf86drmMode.h>
23 #include "lease-manager.h"
25 #include "test-drm-device.h"
26 #include "test-helpers.h"
28 #define INVALID_OBJECT_ID (0)
30 /* CHECK_LEASE_OBJECTS
32 * Checks the list of objects associated with a given lease_index.
33 * Asks the lease manager to create the lease, and checks that
34 * the requested objects are the ones given in the supplied list. */
36 #define CHECK_LEASE_OBJECTS(lease, ...) \
38 lm_lease_grant(g_lm, lease); \
39 uint32_t objs[] = {__VA_ARGS__}; \
40 int nobjs = ARRAY_LEN(objs); \
41 ck_assert_int_eq(drmModeCreateLease_fake.arg2_val, nobjs); \
42 check_uint_array_eq(drmModeCreateLease_fake.arg1_val, objs, \
46 /************** Mock functions *************/
49 FAKE_VALUE_FUNC(drmModeResPtr, drmModeGetResources, int);
50 FAKE_VOID_FUNC(drmModeFreeResources, drmModeResPtr);
51 FAKE_VALUE_FUNC(drmModePlaneResPtr, drmModeGetPlaneResources, int);
52 FAKE_VOID_FUNC(drmModeFreePlaneResources, drmModePlaneResPtr);
54 FAKE_VALUE_FUNC(drmModePlanePtr, drmModeGetPlane, int, uint32_t);
55 FAKE_VOID_FUNC(drmModeFreePlane, drmModePlanePtr);
56 FAKE_VALUE_FUNC(drmModeConnectorPtr, drmModeGetConnector, int, uint32_t);
57 FAKE_VOID_FUNC(drmModeFreeConnector, drmModeConnectorPtr);
58 FAKE_VALUE_FUNC(drmModeEncoderPtr, drmModeGetEncoder, int, uint32_t);
59 FAKE_VOID_FUNC(drmModeFreeEncoder, drmModeEncoderPtr);
61 FAKE_VALUE_FUNC(int, drmModeCreateLease, int, const uint32_t *, int, int,
63 FAKE_VALUE_FUNC(int, drmModeRevokeLease, int, uint32_t);
64 FAKE_VALUE_FUNC(int, drmSetClientCap, int, uint64_t, uint64_t);
66 /************** Test fixutre functions *************************/
67 struct lm *g_lm = NULL;
69 static void test_setup(void)
71 RESET_FAKE(drmModeGetResources);
72 RESET_FAKE(drmModeFreeResources);
73 RESET_FAKE(drmModeGetPlaneResources);
74 RESET_FAKE(drmModeFreePlaneResources);
76 RESET_FAKE(drmModeGetPlane);
77 RESET_FAKE(drmModeFreePlane);
78 RESET_FAKE(drmModeGetConnector);
79 RESET_FAKE(drmModeFreeConnector);
80 RESET_FAKE(drmModeGetEncoder);
81 RESET_FAKE(drmModeFreeEncoder);
83 RESET_FAKE(drmModeCreateLease);
84 RESET_FAKE(drmModeRevokeLease);
86 drmModeGetResources_fake.return_val = TEST_DEVICE_RESOURCES;
87 drmModeGetPlaneResources_fake.return_val = TEST_DEVICE_PLANE_RESOURCES;
89 drmModeGetPlane_fake.custom_fake = get_plane;
90 drmModeGetConnector_fake.custom_fake = get_connector;
91 drmModeGetEncoder_fake.custom_fake = get_encoder;
92 drmModeCreateLease_fake.custom_fake = create_lease;
94 drmSetClientCap_fake.return_val = 0;
96 ck_assert_msg(g_lm == NULL,
97 "Lease manager context not clear at start of test");
100 static void test_shutdown(void)
102 reset_drm_test_device();
107 static struct lease_handle **create_leases(int num_leases,
108 struct lease_config *configs)
112 lm_create_with_config(TEST_DRM_DEVICE, num_leases, configs);
114 g_lm = lm_create(TEST_DRM_DEVICE);
116 ck_assert_ptr_ne(g_lm, NULL);
118 struct lease_handle **handles;
119 ck_assert_int_eq(num_leases, lm_get_lease_handles(g_lm, &handles));
120 ck_assert_ptr_ne(handles, NULL);
125 /************** Resource enumeration tests *************/
127 /* These tests verify that the lease manager correctly assigns
128 * DRM resources to thier respective leases. In some cases
129 * the lease manager must choose which resources to include in
130 * each lease, so these tests verify that a valid (but not
131 * necessarily optimal) choice is made.
134 /* all_outputs_connected
136 * Test details: Create leases when all crtc/encoder/connector paths are
139 * Expected results: Leases are created for the currently connected sets of
142 START_TEST(all_outputs_connected)
144 int out_cnt = 2, plane_cnt = 0;
146 setup_layout_simple_test_device(out_cnt, plane_cnt);
148 struct lease_handle **handles = create_leases(out_cnt, NULL);
150 CHECK_LEASE_OBJECTS(handles[0], CRTC_ID(0), CONNECTOR_ID(0));
151 CHECK_LEASE_OBJECTS(handles[1], CRTC_ID(1), CONNECTOR_ID(1));
155 /* no_outputs_connected
157 * Test details: Create leases when no crtc/encoder/connector paths are
160 * Expected results: Available resources are divided between the leases.
161 * The same resource should not appear in multiple leases.
163 START_TEST(no_outputs_connected)
165 int out_cnt = 2, plane_cnt = 0;
168 setup_drm_test_device(out_cnt, out_cnt, out_cnt, plane_cnt), true);
170 drmModeConnector connectors[] = {
171 CONNECTOR(CONNECTOR_ID(0), 0, &ENCODER_ID(0), 1),
172 CONNECTOR(CONNECTOR_ID(1), 0, &ENCODER_ID(1), 1),
175 drmModeEncoder encoders[] = {
176 ENCODER(ENCODER_ID(0), 0, 0x2),
177 ENCODER(ENCODER_ID(1), 0, 0x3),
180 setup_test_device_layout(connectors, encoders, NULL);
182 g_lm = lm_create(TEST_DRM_DEVICE);
183 ck_assert_ptr_ne(g_lm, NULL);
185 struct lease_handle **handles = create_leases(out_cnt, NULL);
187 CHECK_LEASE_OBJECTS(handles[0], CRTC_ID(1), CONNECTOR_ID(0));
188 CHECK_LEASE_OBJECTS(handles[1], CRTC_ID(0), CONNECTOR_ID(1));
192 /* some_outputs_connected */
193 /* Test details: Create leases when one output is connected and one is not.
194 * Expected results: Currently connected resources should be added to
196 * The non-connected resources should be added to a second
199 START_TEST(some_outputs_connected)
201 int out_cnt = 2, plane_cnt = 0;
204 setup_drm_test_device(out_cnt, out_cnt, out_cnt, plane_cnt), true);
206 drmModeConnector connectors[] = {
207 CONNECTOR(CONNECTOR_ID(0), ENCODER_ID(0), &ENCODER_ID(0), 1),
208 CONNECTOR(CONNECTOR_ID(1), 0, &ENCODER_ID(1), 1),
211 drmModeEncoder encoders[] = {
212 ENCODER(ENCODER_ID(0), CRTC_ID(0), 0x3),
213 ENCODER(ENCODER_ID(1), 0, 0x3),
216 setup_test_device_layout(connectors, encoders, NULL);
218 struct lease_handle **handles = create_leases(out_cnt, NULL);
220 CHECK_LEASE_OBJECTS(handles[0], CRTC_ID(0), CONNECTOR_ID(0));
221 CHECK_LEASE_OBJECTS(handles[1], CRTC_ID(1), CONNECTOR_ID(1));
225 /* fewer_crtcs_than_connectors */
226 /* Test details: Create leases on a system with more connectors than CRTCs
227 * Expected results: Number of leases generated should correspond to number of
229 * Leases contain one valid connector for each CRTC.
231 START_TEST(fewer_crtcs_than_connectors)
233 int out_cnt = 3, plane_cnt = 0, crtc_cnt = 2;
236 setup_drm_test_device(crtc_cnt, out_cnt, out_cnt, plane_cnt), true);
238 drmModeConnector connectors[] = {
239 CONNECTOR(CONNECTOR_ID(0), 0, &ENCODER_ID(0), 1),
240 CONNECTOR(CONNECTOR_ID(1), 0, &ENCODER_ID(1), 1),
241 CONNECTOR(CONNECTOR_ID(2), 0, &ENCODER_ID(2), 1),
244 drmModeEncoder encoders[] = {
245 ENCODER(ENCODER_ID(0), 0, 0x3),
246 ENCODER(ENCODER_ID(1), 0, 0x1),
247 ENCODER(ENCODER_ID(2), 0, 0x3),
250 setup_test_device_layout(connectors, encoders, NULL);
252 struct lease_handle **handles = create_leases(crtc_cnt, NULL);
254 CHECK_LEASE_OBJECTS(handles[0], CRTC_ID(0), CONNECTOR_ID(0));
255 CHECK_LEASE_OBJECTS(handles[1], CRTC_ID(1), CONNECTOR_ID(2));
259 /* separate_overlay_planes_by_crtc */
260 /* Test details: Add overlay planes to leases. Each plane is tied to a
262 * Expected results: The leases contain all of the planes for connected to
263 * each CRTC and no others.
265 START_TEST(separate_overlay_planes_by_crtc)
268 int out_cnt = 2, plane_cnt = 3;
270 setup_layout_simple_test_device(out_cnt, plane_cnt);
272 struct lease_handle **handles = create_leases(out_cnt, NULL);
274 CHECK_LEASE_OBJECTS(handles[0], PLANE_ID(0), PLANE_ID(2), CRTC_ID(0),
276 CHECK_LEASE_OBJECTS(handles[1], PLANE_ID(1), CRTC_ID(1),
281 /* reject_planes_shared_between_multiple_crtcs */
282 /* Test details: Add overlay planes to leases. Some planes are shared between
284 * Expected results: The leases contain all of the unique planes for each CRTC.
285 * Planes that can be used on multiple CRTCs are not included
288 START_TEST(reject_planes_shared_between_multiple_crtcs)
291 int out_cnt = 2, plane_cnt = 3;
294 setup_drm_test_device(out_cnt, out_cnt, out_cnt, plane_cnt), true);
296 drmModeConnector connectors[] = {
297 CONNECTOR(CONNECTOR_ID(0), ENCODER_ID(0), &ENCODER_ID(0), 1),
298 CONNECTOR(CONNECTOR_ID(1), ENCODER_ID(1), &ENCODER_ID(1), 1),
301 drmModeEncoder encoders[] = {
302 ENCODER(ENCODER_ID(0), CRTC_ID(0), 0x1),
303 ENCODER(ENCODER_ID(1), CRTC_ID(1), 0x2),
306 drmModePlane planes[] = {
307 PLANE(PLANE_ID(0), 0x2),
308 PLANE(PLANE_ID(1), 0x1),
309 PLANE(PLANE_ID(2), 0x3),
312 setup_test_device_layout(connectors, encoders, planes);
314 struct lease_handle **handles = create_leases(out_cnt, NULL);
316 CHECK_LEASE_OBJECTS(handles[0], PLANE_ID(1), CRTC_ID(0),
318 CHECK_LEASE_OBJECTS(handles[1], PLANE_ID(0), CRTC_ID(1),
323 static void add_connector_enum_tests(Suite *s)
325 TCase *tc = tcase_create("Resource enumeration");
327 tcase_add_checked_fixture(tc, test_setup, test_shutdown);
329 tcase_add_test(tc, all_outputs_connected);
330 tcase_add_test(tc, no_outputs_connected);
331 tcase_add_test(tc, fewer_crtcs_than_connectors);
332 tcase_add_test(tc, some_outputs_connected);
333 tcase_add_test(tc, separate_overlay_planes_by_crtc);
334 tcase_add_test(tc, reject_planes_shared_between_multiple_crtcs);
335 suite_add_tcase(s, tc);
338 /************** Lease management tests *************/
340 /* create_and_revoke_lease */
341 /* Test details: Create leases and revoke them.
342 * Expected results: drmModeRevokeLease() is called with the correct leasee_id.
344 START_TEST(create_and_revoke_lease)
346 int lease_cnt = 2, plane_cnt = 0;
348 setup_layout_simple_test_device(lease_cnt, plane_cnt);
350 struct lease_handle **handles = create_leases(lease_cnt, NULL);
352 for (int i = 0; i < lease_cnt; i++) {
353 ck_assert_int_ge(lm_lease_grant(g_lm, handles[i]), 0);
354 lm_lease_revoke(g_lm, handles[i]);
357 ck_assert_int_eq(drmModeRevokeLease_fake.call_count, lease_cnt);
359 for (int i = 0; i < lease_cnt; i++) {
360 ck_assert_int_eq(drmModeRevokeLease_fake.arg1_history[i],
366 /* Test lease names */
367 /* Test details: Create some leases and verify that they have the correct names
368 * Expected results: lease names should match the expected values
370 START_TEST(verify_lease_names)
373 bool res = setup_drm_test_device(lease_cnt, lease_cnt, lease_cnt, 0);
374 ck_assert_int_eq(res, true);
376 drmModeConnector connectors[] = {
377 CONNECTOR_FULL(CONNECTOR_ID(0), ENCODER_ID(0), &ENCODER_ID(0), 1,
378 DRM_MODE_CONNECTOR_HDMIA, 1),
379 CONNECTOR_FULL(CONNECTOR_ID(1), ENCODER_ID(1), &ENCODER_ID(1), 1,
380 DRM_MODE_CONNECTOR_LVDS, 3),
381 CONNECTOR_FULL(CONNECTOR_ID(2), ENCODER_ID(2), &ENCODER_ID(2), 1,
382 DRM_MODE_CONNECTOR_eDP, 6),
385 drmModeEncoder encoders[] = {
386 ENCODER(ENCODER_ID(0), CRTC_ID(0), 0x7),
387 ENCODER(ENCODER_ID(1), CRTC_ID(1), 0x7),
388 ENCODER(ENCODER_ID(2), CRTC_ID(2), 0x7),
391 setup_test_device_layout(connectors, encoders, NULL);
393 const char *expected_names[] = {
399 struct lease_handle **handles = create_leases(lease_cnt, NULL);
401 for (int i = 0; i < lease_cnt; i++) {
402 ck_assert_str_eq(handles[i]->name, expected_names[i]);
407 static void add_lease_management_tests(Suite *s)
409 TCase *tc = tcase_create("Lease management");
411 tcase_add_checked_fixture(tc, test_setup, test_shutdown);
413 tcase_add_test(tc, create_and_revoke_lease);
414 tcase_add_test(tc, verify_lease_names);
415 suite_add_tcase(s, tc);
418 /***************** Lease Configuration Tests *************/
420 /* multiple_connector_lease */
421 /* Test details: Create a lease with multipe connectors
422 * Expected results: a lease is created with the CRTC and connector ID for both
425 START_TEST(multiple_connector_lease)
427 int out_cnt = 2, plane_cnt = 0, lease_cnt = 1;
429 setup_layout_simple_test_device(out_cnt, plane_cnt);
431 struct lease_config lconfig = {
432 .lease_name = "Lease Config Test 1",
434 .connector_ids = (uint32_t[]){CONNECTOR_ID(0), CONNECTOR_ID(1)},
437 struct lease_handle **handles = create_leases(lease_cnt, &lconfig);
439 CHECK_LEASE_OBJECTS(handles[0], CRTC_ID(0), CONNECTOR_ID(0), CRTC_ID(1),
444 /* single_failed_lease */
445 /* Test details: Create 2 lease configs. One with valid data, one without.
446 * Expected results: A handle is created for the single valid lease.
448 START_TEST(single_failed_lease)
450 int out_cnt = 3, plane_cnt = 0, success_lease_cnt = 1;
452 setup_layout_simple_test_device(out_cnt, plane_cnt);
454 struct lease_config lconfigs[2] = {
457 .lease_name = "Lease Config Test 1",
459 .connector_ids = (uint32_t[]){INVALID_OBJECT_ID},
463 .lease_name = "Lease Config Test 2",
466 (uint32_t[]){CONNECTOR_ID(0), CONNECTOR_ID(1)},
470 /* Expect fewer leases than configurations supplied, so explicitly
471 * create and check leases. */
472 g_lm = lm_create_with_config(TEST_DRM_DEVICE, ARRAY_LEN(lconfigs),
474 ck_assert_ptr_ne(g_lm, NULL);
476 struct lease_handle **handles;
477 ck_assert_int_eq(success_lease_cnt,
478 lm_get_lease_handles(g_lm, &handles));
479 ck_assert_ptr_ne(handles, NULL);
481 CHECK_LEASE_OBJECTS(handles[0], CRTC_ID(0), CONNECTOR_ID(0), CRTC_ID(1),
486 /* named_connector_config */
487 /* Test details: Test specifying connectors by name in config
488 * Expected results: A handle is created for each named connector
491 START_TEST(named_connector_config)
493 int out_cnt = 2, plane_cnt = 0, lease_cnt = 1;
496 setup_drm_test_device(out_cnt, out_cnt, out_cnt, plane_cnt), true);
498 drmModeConnector connectors[] = {
499 CONNECTOR_FULL(CONNECTOR_ID(0), ENCODER_ID(0), &ENCODER_ID(0), 1,
500 DRM_MODE_CONNECTOR_HDMIA, 1),
501 CONNECTOR_FULL(CONNECTOR_ID(1), ENCODER_ID(1), &ENCODER_ID(1), 1,
502 DRM_MODE_CONNECTOR_VGA, 3),
505 drmModeEncoder encoders[] = {
506 ENCODER(ENCODER_ID(0), CRTC_ID(0), 0x1),
507 ENCODER(ENCODER_ID(1), CRTC_ID(1), 0x2),
510 setup_test_device_layout(connectors, encoders, NULL);
512 struct lease_config lconfig = {
513 .lease_name = "Lease Config Test 1",
516 (struct connector_config[]){
517 {.name = "HDMI-A-1"},
522 struct lease_handle **handles = create_leases(lease_cnt, &lconfig);
524 ck_assert_str_eq(handles[0]->name, lconfig.lease_name);
525 CHECK_LEASE_OBJECTS(handles[0], CRTC_ID(0), CONNECTOR_ID(0), CRTC_ID(1),
530 /* config plane sharing */
531 /* Test details: Add overlay planes to leases. Some planes are shared between
532 * multiple CRTCs. These planes are explicitly assigned to a
533 * connector. Expected results: The leases contain all of the unique planes for
534 * each CRTC. Shared planes are also included as defined by the lease
537 START_TEST(config_plane_sharing)
540 int out_cnt = 2, plane_cnt = 3, lease_cnt = 2;
543 setup_drm_test_device(out_cnt, out_cnt, out_cnt, plane_cnt), true);
545 drmModeConnector connectors[] = {
546 CONNECTOR_FULL(CONNECTOR_ID(0), ENCODER_ID(0), &ENCODER_ID(0), 1,
547 DRM_MODE_CONNECTOR_HDMIA, 1),
548 CONNECTOR_FULL(CONNECTOR_ID(1), ENCODER_ID(1), &ENCODER_ID(1), 1,
549 DRM_MODE_CONNECTOR_VGA, 3),
552 drmModeEncoder encoders[] = {
553 ENCODER(ENCODER_ID(0), CRTC_ID(0), 0x1),
554 ENCODER(ENCODER_ID(1), CRTC_ID(1), 0x2),
557 drmModePlane planes[] = {
558 PLANE(PLANE_ID(0), 0x2),
559 PLANE(PLANE_ID(1), 0x1),
560 PLANE(PLANE_ID(2), 0x3),
563 setup_test_device_layout(connectors, encoders, planes);
565 struct lease_config lconfig[] = {
568 .lease_name = "Lease Config Test 1",
571 (struct connector_config[]){
574 .planes = (uint32_t[]){PLANE_ID(1), PLANE_ID(2)}},
579 .lease_name = "Lease Config Test 2",
582 (struct connector_config[]){
588 struct lease_handle **handles = create_leases(lease_cnt, lconfig);
590 CHECK_LEASE_OBJECTS(handles[0], PLANE_ID(1), PLANE_ID(2), CRTC_ID(0),
592 CHECK_LEASE_OBJECTS(handles[1], PLANE_ID(0), CRTC_ID(1),
597 static void add_lease_config_tests(Suite *s)
599 TCase *tc = tcase_create("Lease configuration");
601 tcase_add_checked_fixture(tc, test_setup, test_shutdown);
603 tcase_add_test(tc, multiple_connector_lease);
604 tcase_add_test(tc, single_failed_lease);
605 tcase_add_test(tc, named_connector_config);
606 tcase_add_test(tc, config_plane_sharing);
607 suite_add_tcase(s, tc);
616 s = suite_create("DLM lease manager tests");
618 add_connector_enum_tests(s);
619 add_lease_management_tests(s);
620 add_lease_config_tests(s);
622 sr = srunner_create(s);
623 srunner_run_all(sr, CK_NORMAL);
624 number_failed = srunner_ntests_failed(sr);
626 return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;