From e7e1f35d703a75496a1579133e0312d4a9761827 Mon Sep 17 00:00:00 2001 From: Damian Hobson-Garcia Date: Thu, 16 Sep 2021 18:07:54 +0900 Subject: log: Add line number to debug log output Some debug logging, such as memory allocation failure, uses similar log messageing in several places. Add the file line number to the debug log to help differentiate where notable errors occured. Bug-AGL: SPEC-3815 Change-Id: I2151e21533716ea0badbb6303b713e644b544e6d Signed-off-by: Damian Hobson-Garcia --- common/log.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/common/log.h b/common/log.h index cd0c0e3..ed3b2db 100644 --- a/common/log.h +++ b/common/log.h @@ -19,8 +19,9 @@ #include #include -#define DEBUG_LOG(FMT, ...) \ - dlm_log_print(true, stdout, "DEBUG: %s: " FMT, __func__, ##__VA_ARGS__) +#define DEBUG_LOG(FMT, ...) \ + dlm_log_print(true, stdout, "DEBUG: %s: line %d: " FMT, __func__, \ + __LINE__, ##__VA_ARGS__) #define INFO_LOG(FMT, ...) \ dlm_log_print(false, stdout, "INFO: " FMT, ##__VA_ARGS__) #define WARN_LOG(FMT, ...) \ -- cgit From d2ada94bcd4e125009d4ccdda7e5a8d01a96efe2 Mon Sep 17 00:00:00 2001 From: Damian Hobson-Garcia Date: Wed, 16 Mar 2022 10:10:39 +0900 Subject: test/lease-manager: Create dummy fds for fake lease grants drmModeCreateLease() should return a new lease fd for every succesful call. Make sure that our dummy implementation does the same. Returning 0 will cause stdout to be closed at the end of each test, which will break the test logging when tests are run without forking (ie. when CK_FORK=no) Bug-AGL: SPEC-3815 Change-Id: I6b9436a962fb25b88576ae1c950c4f6f698e949a Signed-off-by: Damian Hobson-Garcia --- drm-lease-manager/test/test-drm-device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drm-lease-manager/test/test-drm-device.c b/drm-lease-manager/test/test-drm-device.c index 844599a..c024d6e 100644 --- a/drm-lease-manager/test/test-drm-device.c +++ b/drm-lease-manager/test/test-drm-device.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include "test-drm-device.h" @@ -105,7 +106,6 @@ GET_DRM_RESOURCE_FN(Plane, plane, PLANE, plane_resources) int create_lease(int fd, const uint32_t *objects, int num_objects, int flags, uint32_t *lessee_id) { - UNUSED(fd); UNUSED(objects); UNUSED(num_objects); UNUSED(flags); @@ -118,5 +118,5 @@ int create_lease(int fd, const uint32_t *objects, int num_objects, int flags, test_device.leases.count++; - return 0; + return dup(fd); } -- cgit From e81466892689b6814d5e9bf0e80b792bfee47c83 Mon Sep 17 00:00:00 2001 From: Damian Hobson-Garcia Date: Tue, 15 Mar 2022 16:46:49 +0900 Subject: Multi connector lease support Add support for having multiple connectors / CTRCs in a single lease. The lease manager receives a list of lease configurations that specify the name and list of connectors to include in each lease. All DRM planes that are not shared between muliple CRTS are added for each connector contained in the lease. If the lease manager is initialized without a list of lease configurations it will fall back to the previous 1 connector per lease configuration. Bug-AGL: SPEC-3815 Change-Id: I6699e7c8f426bab9fadbc64fe4ed242a834376bf Signed-off-by: Damian Hobson-Garcia --- drm-lease-manager/drm-lease.h | 9 ++ drm-lease-manager/lease-manager.c | 190 ++++++++++++++++++++++++++++++-------- drm-lease-manager/lease-manager.h | 3 + 3 files changed, 165 insertions(+), 37 deletions(-) diff --git a/drm-lease-manager/drm-lease.h b/drm-lease-manager/drm-lease.h index a855054..223c347 100644 --- a/drm-lease-manager/drm-lease.h +++ b/drm-lease-manager/drm-lease.h @@ -15,9 +15,18 @@ #ifndef DRM_LEASE_H #define DRM_LEASE_H +#include struct lease_handle { char *name; void *user_data; }; + +struct lease_config { + char *lease_name; + + int ncids; + uint32_t *connector_ids; +}; + #endif diff --git a/drm-lease-manager/lease-manager.c b/drm-lease-manager/lease-manager.c index 5eeef16..9627f0d 100644 --- a/drm-lease-manager/lease-manager.c +++ b/drm-lease-manager/lease-manager.c @@ -34,9 +34,9 @@ #include #include -/* Number of resources, excluding planes, to be included in each DRM lease. - * Each lease needs at least a CRTC and conector. */ -#define DRM_LEASE_MIN_RES (2) +/* Number of resources, to be included in a DRM lease for each connector. + * Each connector needs both a CRTC and conector object:. */ +#define DRM_OBJECTS_PER_CONNECTOR (2) #define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0])) @@ -90,7 +90,8 @@ static const char *const connector_type_names[] = { [DRM_MODE_CONNECTOR_WRITEBACK] = "Writeback", }; -static char *drm_create_lease_name(struct lm *lm, drmModeConnectorPtr connector) +static char *drm_create_default_lease_name(struct lm *lm, + drmModeConnectorPtr connector) { uint32_t type = connector->connector_type; uint32_t id = connector->connector_type_id; @@ -294,42 +295,67 @@ static void lease_free(struct lease *lease) free(lease); } -static struct lease *lease_create(struct lm *lm, drmModeConnectorPtr connector) +static struct lease *lease_create(struct lm *lm, + const struct lease_config *config) { - struct lease *lease = calloc(1, sizeof(struct lease)); + struct lease *lease; + + if (!config->lease_name) { + ERROR_LOG("Mising lease name\n"); + return NULL; + } + + lease = calloc(1, sizeof(struct lease)); if (!lease) { DEBUG_LOG("Memory allocation failed: %s\n", strerror(errno)); return NULL; } - lease->base.name = drm_create_lease_name(lm, connector); + lease->base.name = strdup(config->lease_name); if (!lease->base.name) { DEBUG_LOG("Can't create lease name: %s\n", strerror(errno)); goto err; } - int nobjects = lm->drm_plane_resource->count_planes + DRM_LEASE_MIN_RES; + int nobjects = lm->drm_plane_resource->count_planes + + config->ncids * DRM_OBJECTS_PER_CONNECTOR; + lease->object_ids = calloc(nobjects, sizeof(uint32_t)); if (!lease->object_ids) { DEBUG_LOG("Memory allocation failed: %s\n", strerror(errno)); goto err; } - int crtc_index = drm_get_crtc_index(lm, connector); - if (crtc_index < 0) { - DEBUG_LOG("No crtc found for connector: %s\n", - lease->base.name); - goto err; - } + for (int i = 0; i < config->ncids; i++) { + drmModeConnectorPtr connector = + drmModeGetConnector(lm->drm_fd, config->connector_ids[i]); - if (!lease_add_planes(lm, lease, crtc_index)) - goto err; + if (connector == NULL) { + ERROR_LOG("Can't find connector id: %d\n", + config->connector_ids); + goto err; + } + + uint32_t connector_id = connector->connector_id; + + int crtc_index = drm_get_crtc_index(lm, connector); + + drmModeFreeConnector(connector); - uint32_t crtc_id = lm->drm_resource->crtcs[crtc_index]; - lease->crtc_id = crtc_id; - lease->object_ids[lease->nobject_ids++] = crtc_id; - lease->object_ids[lease->nobject_ids++] = connector->connector_id; + if (crtc_index < 0) { + DEBUG_LOG("No crtc found for connector: %d, lease %s\n", + connector_id, lease->base.name); + goto err; + } + + if (!lease_add_planes(lm, lease, crtc_index)) + goto err; + uint32_t crtc_id = lm->drm_resource->crtcs[crtc_index]; + lease->crtc_id = crtc_id; + lease->object_ids[lease->nobject_ids++] = crtc_id; + lease->object_ids[lease->nobject_ids++] = connector_id; + } lease->is_granted = false; lease->lease_fd = -1; @@ -340,7 +366,69 @@ err: return NULL; } -struct lm *lm_create(const char *device) +static void destroy_default_lease_configs(int num_configs, + struct lease_config *configs) +{ + for (int i = 0; i < num_configs; i++) { + free(configs[i].connector_ids); + free(configs[i].lease_name); + } + + free(configs); +} + +static int create_default_lease_configs(struct lm *lm, + struct lease_config **configs) +{ + struct lease_config *def_configs; + int num_configs = lm->drm_resource->count_connectors; + + if (num_configs < 0) + return -1; + + def_configs = calloc(num_configs, sizeof(*def_configs)); + if (!def_configs) { + DEBUG_LOG("Memory allocation failed: %s\n", strerror(errno)); + return -1; + } + + for (int i = 0; i < num_configs; i++) { + uint32_t cid = lm->drm_resource->connectors[i]; + + def_configs[i].connector_ids = malloc(sizeof(uint32_t)); + if (!def_configs[i].connector_ids) { + DEBUG_LOG("Memory allocation failed: %s\n", + strerror(errno)); + goto err; + } + + drmModeConnectorPtr connector; + connector = drmModeGetConnector(lm->drm_fd, cid); + def_configs[i].lease_name = + drm_create_default_lease_name(lm, connector); + + if (!def_configs[i].lease_name) { + DEBUG_LOG( + "Can't create lease name for connector %d: %s\n", + cid, strerror(errno)); + goto err; + } + + drmModeFreeConnector(connector); + + def_configs[i].connector_ids[0] = cid; + def_configs[i].ncids = 1; + } + + *configs = def_configs; + return num_configs; + +err: + destroy_default_lease_configs(num_configs, def_configs); + return -1; +} + +static struct lm *drm_device_get_resources(const char *device) { struct lm *lm = calloc(1, sizeof(struct lm)); if (!lm) { @@ -376,27 +464,25 @@ struct lm *lm_create(const char *device) lm->dev_id = st.st_rdev; - int num_leases = lm->drm_resource->count_connectors; + return lm; +err: + lm_destroy(lm); + return NULL; +} +static int lm_create_leases(struct lm *lm, int num_leases, + const struct lease_config *configs) +{ lm->leases = calloc(num_leases, sizeof(struct lease *)); if (!lm->leases) { DEBUG_LOG("Memory allocation failed: %s\n", strerror(errno)); - goto err; + return -1; } drm_find_available_crtcs(lm); for (int i = 0; i < num_leases; i++) { - uint32_t connector_id = lm->drm_resource->connectors[i]; - drmModeConnectorPtr connector = - drmModeGetConnector(lm->drm_fd, connector_id); - - if (!connector) - continue; - - struct lease *lease = lease_create(lm, connector); - drmModeFreeConnector(connector); - + struct lease *lease = lease_create(lm, &configs[i]); if (!lease) continue; @@ -404,13 +490,43 @@ struct lm *lm_create(const char *device) lm->nleases++; } if (lm->nleases == 0) - goto err; + return -1; + + return 0; +} + +struct lm *lm_create_with_config(const char *device, int num_leases, + struct lease_config *configs) +{ + struct lease_config *default_configs = NULL; + struct lm *lm = drm_device_get_resources(device); + + if (!lm) + return NULL; + + if (configs == NULL) { + num_leases = create_default_lease_configs(lm, &default_configs); + if (num_leases < 0) { + lm_destroy(lm); + ERROR_LOG("DRM connector enumeration failed\n"); + return NULL; + } + configs = default_configs; + } + if (lm_create_leases(lm, num_leases, configs) < 0) { + lm_destroy(lm); + lm = NULL; + } + + if (default_configs) + destroy_default_lease_configs(num_leases, default_configs); return lm; +} -err: - lm_destroy(lm); - return NULL; +struct lm *lm_create(const char *device) +{ + return lm_create_with_config(device, 0, NULL); } void lm_destroy(struct lm *lm) diff --git a/drm-lease-manager/lease-manager.h b/drm-lease-manager/lease-manager.h index 55bf81e..d13ca43 100644 --- a/drm-lease-manager/lease-manager.h +++ b/drm-lease-manager/lease-manager.h @@ -20,6 +20,9 @@ struct lm; struct lm *lm_create(const char *path); +struct lm *lm_create_with_config(const char *path, int leases, + struct lease_config *configs); + void lm_destroy(struct lm *lm); int lm_get_lease_handles(struct lm *lm, struct lease_handle ***lease_handles); -- cgit From e39cb4f5d10e162bc7a5a5a173581c1924d475ea Mon Sep 17 00:00:00 2001 From: Damian Hobson-Garcia Date: Tue, 28 Sep 2021 17:07:32 +0900 Subject: test/drm-lease: Create helper functions to reduce boilerplate Most of the test cases use very similar setup code to configure the test DRM device and leases. Refactor this out into separate functions to help keep the focus on the relevant parts of each test. The helpers set up a basic DRM device with one 1:1 mapping of encoders, CRTCs, and connectors, with support for planes. Tests that don't adhere to this pattern are likely testing for a specific configuration, so should be open coding their setup. Bug-AGL: SPEC-3815 Change-Id: I0adbed04246ff6af0060692fa4c1e5897b903237 Signed-off-by: Damian Hobson-Garcia --- drm-lease-manager/test/lease-manager-test.c | 145 ++++++++-------------------- drm-lease-manager/test/test-drm-device.c | 43 +++++++++ drm-lease-manager/test/test-drm-device.h | 2 + 3 files changed, 87 insertions(+), 103 deletions(-) diff --git a/drm-lease-manager/test/lease-manager-test.c b/drm-lease-manager/test/lease-manager-test.c index c741cb3..5d19992 100644 --- a/drm-lease-manager/test/lease-manager-test.c +++ b/drm-lease-manager/test/lease-manager-test.c @@ -33,7 +33,7 @@ #define CHECK_LEASE_OBJECTS(lease, ...) \ do { \ - lm_lease_grant(lm, lease); \ + lm_lease_grant(g_lm, lease); \ uint32_t objs[] = {__VA_ARGS__}; \ int nobjs = ARRAY_LEN(objs); \ ck_assert_int_eq(drmModeCreateLease_fake.arg2_val, nobjs); \ @@ -61,6 +61,7 @@ FAKE_VALUE_FUNC(int, drmModeCreateLease, int, const uint32_t *, int, int, FAKE_VALUE_FUNC(int, drmModeRevokeLease, int, uint32_t); /************** Test fixutre functions *************************/ +struct lm *g_lm = NULL; static void test_setup(void) { @@ -86,11 +87,34 @@ static void test_setup(void) drmModeGetConnector_fake.custom_fake = get_connector; drmModeGetEncoder_fake.custom_fake = get_encoder; drmModeCreateLease_fake.custom_fake = create_lease; + + ck_assert_msg(g_lm == NULL, + "Lease manager context not clear at start of test"); } static void test_shutdown(void) { reset_drm_test_device(); + lm_destroy(g_lm); + g_lm = NULL; +} + +static struct lease_handle **create_leases(int num_leases, + struct lease_config *configs) +{ + if (configs) + g_lm = + lm_create_with_config(TEST_DRM_DEVICE, num_leases, configs); + else + g_lm = lm_create(TEST_DRM_DEVICE); + + ck_assert_ptr_ne(g_lm, NULL); + + struct lease_handle **handles; + ck_assert_int_eq(num_leases, lm_get_lease_handles(g_lm, &handles)); + ck_assert_ptr_ne(handles, NULL); + + return handles; } /************** Resource enumeration tests *************/ @@ -114,32 +138,12 @@ START_TEST(all_outputs_connected) { int out_cnt = 2, plane_cnt = 0; - ck_assert_int_eq( - setup_drm_test_device(out_cnt, out_cnt, out_cnt, plane_cnt), true); - - drmModeConnector connectors[] = { - CONNECTOR(CONNECTOR_ID(0), ENCODER_ID(0), &ENCODER_ID(0), 1), - CONNECTOR(CONNECTOR_ID(1), ENCODER_ID(1), &ENCODER_ID(1), 1), - }; + setup_layout_simple_test_device(out_cnt, plane_cnt); - drmModeEncoder encoders[] = { - ENCODER(ENCODER_ID(0), CRTC_ID(0), 0x3), - ENCODER(ENCODER_ID(1), CRTC_ID(1), 0x2), - }; - - setup_test_device_layout(connectors, encoders, NULL); - - struct lm *lm = lm_create(TEST_DRM_DEVICE); - ck_assert_ptr_ne(lm, NULL); - - struct lease_handle **handles; - ck_assert_int_eq(out_cnt, lm_get_lease_handles(lm, &handles)); - ck_assert_ptr_ne(handles, NULL); + struct lease_handle **handles = create_leases(out_cnt, NULL); CHECK_LEASE_OBJECTS(handles[0], CRTC_ID(0), CONNECTOR_ID(0)); CHECK_LEASE_OBJECTS(handles[1], CRTC_ID(1), CONNECTOR_ID(1)); - - lm_destroy(lm); } END_TEST @@ -170,17 +174,13 @@ START_TEST(no_outputs_connected) setup_test_device_layout(connectors, encoders, NULL); - struct lm *lm = lm_create(TEST_DRM_DEVICE); - ck_assert_ptr_ne(lm, NULL); + g_lm = lm_create(TEST_DRM_DEVICE); + ck_assert_ptr_ne(g_lm, NULL); - struct lease_handle **handles; - ck_assert_int_eq(out_cnt, lm_get_lease_handles(lm, &handles)); - ck_assert_ptr_ne(handles, NULL); + struct lease_handle **handles = create_leases(out_cnt, NULL); CHECK_LEASE_OBJECTS(handles[0], CRTC_ID(1), CONNECTOR_ID(0)); CHECK_LEASE_OBJECTS(handles[1], CRTC_ID(0), CONNECTOR_ID(1)); - - lm_destroy(lm); } END_TEST @@ -210,17 +210,10 @@ START_TEST(some_outputs_connected) setup_test_device_layout(connectors, encoders, NULL); - struct lm *lm = lm_create(TEST_DRM_DEVICE); - ck_assert_ptr_ne(lm, NULL); - - struct lease_handle **handles; - ck_assert_int_eq(out_cnt, lm_get_lease_handles(lm, &handles)); - ck_assert_ptr_ne(handles, NULL); + struct lease_handle **handles = create_leases(out_cnt, NULL); CHECK_LEASE_OBJECTS(handles[0], CRTC_ID(0), CONNECTOR_ID(0)); CHECK_LEASE_OBJECTS(handles[1], CRTC_ID(1), CONNECTOR_ID(1)); - - lm_destroy(lm); } END_TEST @@ -251,16 +244,10 @@ START_TEST(fewer_crtcs_than_connectors) setup_test_device_layout(connectors, encoders, NULL); - struct lm *lm = lm_create(TEST_DRM_DEVICE); - ck_assert_ptr_ne(lm, NULL); - - struct lease_handle **handles; - ck_assert_int_eq(lm_get_lease_handles(lm, &handles), crtc_cnt); - ck_assert_ptr_ne(handles, NULL); + struct lease_handle **handles = create_leases(crtc_cnt, NULL); CHECK_LEASE_OBJECTS(handles[0], CRTC_ID(0), CONNECTOR_ID(0)); CHECK_LEASE_OBJECTS(handles[1], CRTC_ID(1), CONNECTOR_ID(2)); - lm_destroy(lm); } END_TEST @@ -275,39 +262,14 @@ START_TEST(separate_overlay_planes_by_crtc) int out_cnt = 2, plane_cnt = 3; - ck_assert_int_eq( - setup_drm_test_device(out_cnt, out_cnt, out_cnt, plane_cnt), true); + setup_layout_simple_test_device(out_cnt, plane_cnt); - drmModeConnector connectors[] = { - CONNECTOR(CONNECTOR_ID(0), ENCODER_ID(0), &ENCODER_ID(0), 1), - CONNECTOR(CONNECTOR_ID(1), ENCODER_ID(1), &ENCODER_ID(1), 1), - }; - - drmModeEncoder encoders[] = { - ENCODER(ENCODER_ID(0), CRTC_ID(0), 0x1), - ENCODER(ENCODER_ID(1), CRTC_ID(1), 0x2), - }; - - drmModePlane planes[] = { - PLANE(PLANE_ID(0), 0x2), - PLANE(PLANE_ID(1), 0x1), - PLANE(PLANE_ID(2), 0x2), - }; - - setup_test_device_layout(connectors, encoders, planes); - - struct lm *lm = lm_create(TEST_DRM_DEVICE); - ck_assert_ptr_ne(lm, NULL); - - struct lease_handle **handles; - ck_assert_int_eq(out_cnt, lm_get_lease_handles(lm, &handles)); - ck_assert_ptr_ne(handles, NULL); + struct lease_handle **handles = create_leases(out_cnt, NULL); - CHECK_LEASE_OBJECTS(handles[0], PLANE_ID(1), CRTC_ID(0), + CHECK_LEASE_OBJECTS(handles[0], PLANE_ID(0), PLANE_ID(2), CRTC_ID(0), CONNECTOR_ID(0)); - CHECK_LEASE_OBJECTS(handles[1], PLANE_ID(0), PLANE_ID(2), CRTC_ID(1), + CHECK_LEASE_OBJECTS(handles[1], PLANE_ID(1), CRTC_ID(1), CONNECTOR_ID(1)); - lm_destroy(lm); } END_TEST @@ -344,18 +306,12 @@ START_TEST(reject_planes_shared_between_multiple_crtcs) setup_test_device_layout(connectors, encoders, planes); - struct lm *lm = lm_create(TEST_DRM_DEVICE); - ck_assert_ptr_ne(lm, NULL); - - struct lease_handle **handles; - ck_assert_int_eq(out_cnt, lm_get_lease_handles(lm, &handles)); - ck_assert_ptr_ne(handles, NULL); + struct lease_handle **handles = create_leases(out_cnt, NULL); CHECK_LEASE_OBJECTS(handles[0], PLANE_ID(1), CRTC_ID(0), CONNECTOR_ID(0)); CHECK_LEASE_OBJECTS(handles[1], PLANE_ID(0), CRTC_ID(1), CONNECTOR_ID(1)); - lm_destroy(lm); } END_TEST @@ -382,32 +338,15 @@ static void add_connector_enum_tests(Suite *s) */ START_TEST(create_and_revoke_lease) { - int lease_cnt = 2; - bool res = setup_drm_test_device(lease_cnt, lease_cnt, lease_cnt, 0); - ck_assert_int_eq(res, true); + int lease_cnt = 2, plane_cnt = 0; - drmModeConnector connectors[] = { - CONNECTOR(CONNECTOR_ID(0), ENCODER_ID(0), &ENCODER_ID(0), 1), - CONNECTOR(CONNECTOR_ID(1), ENCODER_ID(1), &ENCODER_ID(1), 1), - }; + setup_layout_simple_test_device(lease_cnt, plane_cnt); - drmModeEncoder encoders[] = { - ENCODER(ENCODER_ID(0), CRTC_ID(0), 0x1), - ENCODER(ENCODER_ID(1), CRTC_ID(1), 0x2), - }; - - setup_test_device_layout(connectors, encoders, NULL); - - struct lm *lm = lm_create(TEST_DRM_DEVICE); - ck_assert_ptr_ne(lm, NULL); - - struct lease_handle **handles; - ck_assert_int_eq(lease_cnt, lm_get_lease_handles(lm, &handles)); - ck_assert_ptr_ne(handles, NULL); + struct lease_handle **handles = create_leases(lease_cnt, NULL); for (int i = 0; i < lease_cnt; i++) { - ck_assert_int_ge(lm_lease_grant(lm, handles[i]), 0); - lm_lease_revoke(lm, handles[i]); + ck_assert_int_ge(lm_lease_grant(g_lm, handles[i]), 0); + lm_lease_revoke(g_lm, handles[i]); } ck_assert_int_eq(drmModeRevokeLease_fake.call_count, lease_cnt); diff --git a/drm-lease-manager/test/test-drm-device.c b/drm-lease-manager/test/test-drm-device.c index c024d6e..1d1e096 100644 --- a/drm-lease-manager/test/test-drm-device.c +++ b/drm-lease-manager/test/test-drm-device.c @@ -76,6 +76,13 @@ void reset_drm_test_device(void) free(test_device.resources.encoders); free(test_device.plane_resources.planes); free(test_device.leases.lessee_ids); + + if (test_device.layout.free_on_reset) { + free(test_device.layout.connectors); + free(test_device.layout.encoders); + free(test_device.layout.planes); + } + memset(&test_device, 0, sizeof(test_device)); } @@ -87,6 +94,42 @@ void setup_test_device_layout(drmModeConnector *connectors, test_device.layout.planes = planes; } +void setup_layout_simple_test_device(int conn_cnt, int plane_cnt) +{ + drmModeConnector *connectors; + drmModeEncoder *encoders; + drmModePlane *planes = NULL; + + ck_assert_int_ge(conn_cnt, 1); + + setup_drm_test_device(conn_cnt, conn_cnt, conn_cnt, plane_cnt); + + ck_assert_ptr_ne( + connectors = calloc(sizeof(drmModeConnector), conn_cnt), NULL); + ck_assert_ptr_ne(encoders = calloc(sizeof(drmModeEncoder), conn_cnt), + NULL); + + if (plane_cnt > 0) + ck_assert_ptr_ne( + planes = calloc(sizeof(drmModePlane), plane_cnt), NULL); + + int crtc_mask = (1 << conn_cnt) - 1; + for (int i = 0; i < conn_cnt; i++) { + connectors[i] = (drmModeConnector)CONNECTOR( + CONNECTOR_ID(i), ENCODER_ID(i), &ENCODER_ID(i), 1); + encoders[i] = (drmModeEncoder)ENCODER(ENCODER_ID(i), CRTC_ID(i), + crtc_mask); + } + + for (int i = 0; i < plane_cnt; i++) { + planes[i] = + (drmModePlane)PLANE(PLANE_ID(i), 1 << (i % conn_cnt)); + } + + setup_test_device_layout(connectors, encoders, planes); + test_device.layout.free_on_reset = true; +} + #define GET_DRM_RESOURCE_FN(Res, res, RES, container) \ drmMode##Res##Ptr get_##res(int fd, uint32_t id) \ { \ diff --git a/drm-lease-manager/test/test-drm-device.h b/drm-lease-manager/test/test-drm-device.h index 1d5b683..e2e5f52 100644 --- a/drm-lease-manager/test/test-drm-device.h +++ b/drm-lease-manager/test/test-drm-device.h @@ -30,6 +30,7 @@ struct drm_device { drmModeConnector *connectors; drmModeEncoder *encoders; drmModePlane *planes; + bool free_on_reset; } layout; struct { @@ -44,6 +45,7 @@ extern struct drm_device test_device; bool setup_drm_test_device(int crtcs, int connectors, int encoders, int planes); void setup_test_device_layout(drmModeConnector *connectors, drmModeEncoder *encoders, drmModePlane *planes); +void setup_layout_simple_test_device(int connectors, int planes); void reset_drm_test_device(void); drmModeConnectorPtr get_connector(int fd, uint32_t id); -- cgit From 1915c4dd21f4b77886d66f7993a5ad4c09512363 Mon Sep 17 00:00:00 2001 From: Damian Hobson-Garcia Date: Tue, 15 Mar 2022 17:56:07 +0900 Subject: Add test cases for multi-connector lease Bug-AGL: SPEC-3815 Change-Id: I44fa7045980cafd6dbe8d119ee6aee83ea8f6a17 Signed-off-by: Damian Hobson-Garcia --- drm-lease-manager/test/lease-manager-test.c | 82 +++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/drm-lease-manager/test/lease-manager-test.c b/drm-lease-manager/test/lease-manager-test.c index 5d19992..eb4f1b3 100644 --- a/drm-lease-manager/test/lease-manager-test.c +++ b/drm-lease-manager/test/lease-manager-test.c @@ -25,6 +25,8 @@ #include "test-drm-device.h" #include "test-helpers.h" +#define INVALID_OBJECT_ID (0) + /* CHECK_LEASE_OBJECTS * * Checks the list of objects associated with a given lease_index. @@ -368,6 +370,85 @@ static void add_lease_management_tests(Suite *s) suite_add_tcase(s, tc); } +/***************** Lease Configuration Tests *************/ + +/* multiple_connector_lease */ +/* Test details: Create a lease with multipe connectors + * Expected results: a lease is created with the CRTC and connector ID for both + * connectors. + */ +START_TEST(multiple_connector_lease) +{ + int out_cnt = 2, plane_cnt = 0, lease_cnt = 1; + + setup_layout_simple_test_device(out_cnt, plane_cnt); + + struct lease_config lconfig = { + .lease_name = "Lease Config Test 1", + .ncids = 2, + .connector_ids = (uint32_t[]){CONNECTOR_ID(0), CONNECTOR_ID(1)}, + }; + + struct lease_handle **handles = create_leases(lease_cnt, &lconfig); + + CHECK_LEASE_OBJECTS(handles[0], CRTC_ID(0), CONNECTOR_ID(0), CRTC_ID(1), + CONNECTOR_ID(1)); +} +END_TEST + +/* single_failed_lease */ +/* Test details: Create 2 lease configs. One with valid data, one without. + * Expected results: A handle is created for the single valid lease. + */ +START_TEST(single_failed_lease) +{ + int out_cnt = 3, plane_cnt = 0, success_lease_cnt = 1; + + setup_layout_simple_test_device(out_cnt, plane_cnt); + + struct lease_config lconfigs[2] = { + [0] = + { + .lease_name = "Lease Config Test 1", + .ncids = 1, + .connector_ids = (uint32_t[]){INVALID_OBJECT_ID}, + }, + [1] = + { + .lease_name = "Lease Config Test 2", + .ncids = 2, + .connector_ids = + (uint32_t[]){CONNECTOR_ID(0), CONNECTOR_ID(1)}, + }, + }; + + /* Expect fewer leases than configurations supplied, so explicitly + * create and check leases. */ + g_lm = lm_create_with_config(TEST_DRM_DEVICE, ARRAY_LEN(lconfigs), + lconfigs); + ck_assert_ptr_ne(g_lm, NULL); + + struct lease_handle **handles; + ck_assert_int_eq(success_lease_cnt, + lm_get_lease_handles(g_lm, &handles)); + ck_assert_ptr_ne(handles, NULL); + + CHECK_LEASE_OBJECTS(handles[0], CRTC_ID(0), CONNECTOR_ID(0), CRTC_ID(1), + CONNECTOR_ID(1)); +} +END_TEST + +static void add_lease_config_tests(Suite *s) +{ + TCase *tc = tcase_create("Lease configuration"); + + tcase_add_checked_fixture(tc, test_setup, test_shutdown); + + tcase_add_test(tc, multiple_connector_lease); + tcase_add_test(tc, single_failed_lease); + suite_add_tcase(s, tc); +} + int main(void) { int number_failed; @@ -378,6 +459,7 @@ int main(void) add_connector_enum_tests(s); add_lease_management_tests(s); + add_lease_config_tests(s); sr = srunner_create(s); srunner_run_all(sr, CK_NORMAL); -- cgit From 18f563d376f2e1e5d5464a9e2846163b2bdaf25b Mon Sep 17 00:00:00 2001 From: Damian Hobson-Garcia Date: Tue, 5 Apr 2022 12:11:35 +0900 Subject: Add connector name option Refer to connectors by their human-friendly names in lease configuration. The default 1 connector / lease configuration will continue to use lists of connector_ids to avoid unnecessary string conversions. Connector names take precendence over connector_ids in the configuration. i.e. if connector names are present all connector_id values are ignored. Bug-AGL: SPEC-3815 Change-Id: Idb14c1b6ccc68e327d2d154aac48b44d0c6022a8 Signed-off-by: Damian Hobson-Garcia --- drm-lease-manager/drm-lease.h | 3 ++ drm-lease-manager/lease-manager.c | 102 ++++++++++++++++++++++++++++---------- 2 files changed, 79 insertions(+), 26 deletions(-) diff --git a/drm-lease-manager/drm-lease.h b/drm-lease-manager/drm-lease.h index 223c347..76f0bd7 100644 --- a/drm-lease-manager/drm-lease.h +++ b/drm-lease-manager/drm-lease.h @@ -27,6 +27,9 @@ struct lease_config { int ncids; uint32_t *connector_ids; + + int cnames; + char **connector_names; }; #endif diff --git a/drm-lease-manager/lease-manager.c b/drm-lease-manager/lease-manager.c index 9627f0d..b339037 100644 --- a/drm-lease-manager/lease-manager.c +++ b/drm-lease-manager/lease-manager.c @@ -64,6 +64,9 @@ struct lm { drmModePlaneResPtr drm_plane_resource; uint32_t available_crtcs; + char **connector_names; + int nconnectors; + struct lease **leases; int nleases; }; @@ -90,8 +93,7 @@ static const char *const connector_type_names[] = { [DRM_MODE_CONNECTOR_WRITEBACK] = "Writeback", }; -static char *drm_create_default_lease_name(struct lm *lm, - drmModeConnectorPtr connector) +static char *drm_create_connector_name(drmModeConnectorPtr connector) { uint32_t type = connector->connector_type; uint32_t id = connector->connector_type_id; @@ -105,8 +107,18 @@ static char *drm_create_default_lease_name(struct lm *lm, id = connector->connector_id; char *name; - if (asprintf(&name, "card%d-%s-%d", minor(lm->dev_id), - connector_type_names[type], id) < 0) + if (asprintf(&name, "%s-%d", connector_type_names[type], id) < 0) + return NULL; + + return name; +} + +static char *drm_create_default_lease_name(struct lm *lm, int cindex) +{ + char *connector_name = lm->connector_names[cindex]; + + char *name; + if (asprintf(&name, "card%d-%s", minor(lm->dev_id), connector_name) < 0) return NULL; return name; @@ -190,6 +202,20 @@ static void drm_find_available_crtcs(struct lm *lm) } } +static bool drm_find_connector(struct lm *lm, char *name, uint32_t *id) +{ + int connectors = lm->drm_resource->count_connectors; + + for (int i = 0; i < connectors; i++) { + if (strcmp(lm->connector_names[i], name)) + continue; + if (id) + *id = lm->drm_resource->connectors[i]; + return true; + } + return false; +} + static bool lease_add_planes(struct lm *lm, struct lease *lease, int crtc_index) { for (uint32_t i = 0; i < lm->drm_plane_resource->count_planes; i++) { @@ -317,8 +343,9 @@ static struct lease *lease_create(struct lm *lm, goto err; } + int nconnectors = config->cnames > 0 ? config->cnames : config->ncids; int nobjects = lm->drm_plane_resource->count_planes + - config->ncids * DRM_OBJECTS_PER_CONNECTOR; + nconnectors * DRM_OBJECTS_PER_CONNECTOR; lease->object_ids = calloc(nobjects, sizeof(uint32_t)); if (!lease->object_ids) { @@ -326,25 +353,37 @@ static struct lease *lease_create(struct lm *lm, goto err; } - for (int i = 0; i < config->ncids; i++) { + for (int i = 0; i < nconnectors; i++) { + uint32_t cid; + + if (config->cnames > 0) { + char *connector_name = config->connector_names[i]; + + if (!drm_find_connector(lm, connector_name, &cid)) { + WARN_LOG("Lease: %s, " + "unknown DRM connector: %s\n", + config->lease_name, connector_name); + continue; + } + } else { + cid = config->connector_ids[i]; + } + drmModeConnectorPtr connector = - drmModeGetConnector(lm->drm_fd, config->connector_ids[i]); + drmModeGetConnector(lm->drm_fd, cid); if (connector == NULL) { - ERROR_LOG("Can't find connector id: %d\n", - config->connector_ids); + ERROR_LOG("Can't find connector id: %d\n", cid); goto err; } - uint32_t connector_id = connector->connector_id; - int crtc_index = drm_get_crtc_index(lm, connector); drmModeFreeConnector(connector); if (crtc_index < 0) { DEBUG_LOG("No crtc found for connector: %d, lease %s\n", - connector_id, lease->base.name); + cid, lease->base.name); goto err; } @@ -354,7 +393,7 @@ static struct lease *lease_create(struct lm *lm, uint32_t crtc_id = lm->drm_resource->crtcs[crtc_index]; lease->crtc_id = crtc_id; lease->object_ids[lease->nobject_ids++] = crtc_id; - lease->object_ids[lease->nobject_ids++] = connector_id; + lease->object_ids[lease->nobject_ids++] = cid; } lease->is_granted = false; lease->lease_fd = -1; @@ -402,19 +441,8 @@ static int create_default_lease_configs(struct lm *lm, goto err; } - drmModeConnectorPtr connector; - connector = drmModeGetConnector(lm->drm_fd, cid); def_configs[i].lease_name = - drm_create_default_lease_name(lm, connector); - - if (!def_configs[i].lease_name) { - DEBUG_LOG( - "Can't create lease name for connector %d: %s\n", - cid, strerror(errno)); - goto err; - } - - drmModeFreeConnector(connector); + drm_create_default_lease_name(lm, i); def_configs[i].connector_ids[0] = cid; def_configs[i].ncids = 1; @@ -464,6 +492,23 @@ static struct lm *drm_device_get_resources(const char *device) lm->dev_id = st.st_rdev; + lm->nconnectors = lm->drm_resource->count_connectors; + lm->connector_names = calloc(lm->nconnectors, sizeof(char *)); + + for (int i = 0; i < lm->nconnectors; i++) { + drmModeConnectorPtr connector; + uint32_t cid = lm->drm_resource->connectors[i]; + + connector = drmModeGetConnector(lm->drm_fd, cid); + lm->connector_names[i] = drm_create_connector_name(connector); + drmModeFreeConnector(connector); + + if (!lm->connector_names[i]) { + DEBUG_LOG("Can't create name for connector %d: %s\n", + cid, strerror(errno)); + goto err; + } + } return lm; err: lm_destroy(lm); @@ -504,7 +549,7 @@ struct lm *lm_create_with_config(const char *device, int num_leases, if (!lm) return NULL; - if (configs == NULL) { + if (configs == NULL || num_leases == 0) { num_leases = create_default_lease_configs(lm, &default_configs); if (num_leases < 0) { lm_destroy(lm); @@ -541,6 +586,11 @@ void lm_destroy(struct lm *lm) } free(lm->leases); + + for (int i = 0; i < lm->nconnectors; i++) + free(lm->connector_names[i]); + free(lm->connector_names); + drmModeFreeResources(lm->drm_resource); drmModeFreePlaneResources(lm->drm_plane_resource); close(lm->drm_fd); -- cgit From 7141d79aa1ee4cc020e41003319c50234950c8aa Mon Sep 17 00:00:00 2001 From: Damian Hobson-Garcia Date: Wed, 13 Apr 2022 17:35:42 +0900 Subject: test/lease-manager: Add named lease tests Add tests for named connectors in lease configurations. Also ensure that the naming convention is not broken when no lease configuration is given. Bug-AGL: SPEC-3815 Change-Id: I1e4c591183a2f0c155bedc6b71a37b37a2b01451 Signed-off-by: Damian Hobson-Garcia --- drm-lease-manager/test/lease-manager-test.c | 83 +++++++++++++++++++++++++++++ drm-lease-manager/test/meson.build | 6 +++ drm-lease-manager/test/test-drm-device.h | 12 +++-- 3 files changed, 97 insertions(+), 4 deletions(-) diff --git a/drm-lease-manager/test/lease-manager-test.c b/drm-lease-manager/test/lease-manager-test.c index eb4f1b3..f6524ab 100644 --- a/drm-lease-manager/test/lease-manager-test.c +++ b/drm-lease-manager/test/lease-manager-test.c @@ -360,6 +360,47 @@ START_TEST(create_and_revoke_lease) } END_TEST +/* Test lease names */ +/* Test details: Create some leases and verify that they have the correct names + * Expected results: lease names should match the expected values + */ +START_TEST(verify_lease_names) +{ + int lease_cnt = 3; + bool res = setup_drm_test_device(lease_cnt, lease_cnt, lease_cnt, 0); + ck_assert_int_eq(res, true); + + drmModeConnector connectors[] = { + CONNECTOR_FULL(CONNECTOR_ID(0), ENCODER_ID(0), &ENCODER_ID(0), 1, + DRM_MODE_CONNECTOR_HDMIA, 1), + CONNECTOR_FULL(CONNECTOR_ID(1), ENCODER_ID(1), &ENCODER_ID(1), 1, + DRM_MODE_CONNECTOR_LVDS, 3), + CONNECTOR_FULL(CONNECTOR_ID(2), ENCODER_ID(2), &ENCODER_ID(2), 1, + DRM_MODE_CONNECTOR_eDP, 6), + }; + + drmModeEncoder encoders[] = { + ENCODER(ENCODER_ID(0), CRTC_ID(0), 0x7), + ENCODER(ENCODER_ID(1), CRTC_ID(1), 0x7), + ENCODER(ENCODER_ID(2), CRTC_ID(2), 0x7), + }; + + setup_test_device_layout(connectors, encoders, NULL); + + const char *expected_names[] = { + "card3-HDMI-A-1", + "card3-LVDS-3", + "card3-eDP-6", + }; + + struct lease_handle **handles = create_leases(lease_cnt, NULL); + + for (int i = 0; i < lease_cnt; i++) { + ck_assert_str_eq(handles[i]->name, expected_names[i]); + } +} +END_TEST + static void add_lease_management_tests(Suite *s) { TCase *tc = tcase_create("Lease management"); @@ -367,6 +408,7 @@ static void add_lease_management_tests(Suite *s) tcase_add_checked_fixture(tc, test_setup, test_shutdown); tcase_add_test(tc, create_and_revoke_lease); + tcase_add_test(tc, verify_lease_names); suite_add_tcase(s, tc); } @@ -438,6 +480,46 @@ START_TEST(single_failed_lease) } END_TEST +/* named_connector_config */ +/* Test details: Test specifying connectors by name in config + * Expected results: A handle is created for each named connector + */ + +START_TEST(named_connector_config) +{ + int out_cnt = 2, plane_cnt = 0, lease_cnt = 1; + + ck_assert_int_eq( + setup_drm_test_device(out_cnt, out_cnt, out_cnt, plane_cnt), true); + + drmModeConnector connectors[] = { + CONNECTOR_FULL(CONNECTOR_ID(0), ENCODER_ID(0), &ENCODER_ID(0), 1, + DRM_MODE_CONNECTOR_HDMIA, 1), + CONNECTOR_FULL(CONNECTOR_ID(1), ENCODER_ID(1), &ENCODER_ID(1), 1, + DRM_MODE_CONNECTOR_VGA, 3), + }; + + drmModeEncoder encoders[] = { + ENCODER(ENCODER_ID(0), CRTC_ID(0), 0x1), + ENCODER(ENCODER_ID(1), CRTC_ID(1), 0x2), + }; + + setup_test_device_layout(connectors, encoders, NULL); + + struct lease_config lconfig = { + .lease_name = "Lease Config Test 1", + .cnames = 2, + .connector_names = (char *[]){"HDMI-A-1", "VGA-3"}, + }; + + struct lease_handle **handles = create_leases(lease_cnt, &lconfig); + + ck_assert_str_eq(handles[0]->name, lconfig.lease_name); + CHECK_LEASE_OBJECTS(handles[0], CRTC_ID(0), CONNECTOR_ID(0), CRTC_ID(1), + CONNECTOR_ID(1)); +} +END_TEST + static void add_lease_config_tests(Suite *s) { TCase *tc = tcase_create("Lease configuration"); @@ -446,6 +528,7 @@ static void add_lease_config_tests(Suite *s) tcase_add_test(tc, multiple_connector_lease); tcase_add_test(tc, single_failed_lease); + tcase_add_test(tc, named_connector_config); suite_add_tcase(s, tc); } diff --git a/drm-lease-manager/test/meson.build b/drm-lease-manager/test/meson.build index 7d42bec..bb97274 100644 --- a/drm-lease-manager/test/meson.build +++ b/drm-lease-manager/test/meson.build @@ -2,6 +2,10 @@ check_dep = dependency('check') ls_inc = include_directories('..') +test_c_args = [ + '-Wno-missing-field-initializers', #not all tests explicitly initialize all lease config fields +] + ls_objects = main.extract_objects(lease_server_files) ls_test_sources = [ 'lease-server-test.c', @@ -12,6 +16,7 @@ ls_test = executable('lease-server-test', sources: ls_test_sources, objects: ls_objects, dependencies: [check_dep, fff_dep, dlmcommon_dep, thread_dep], + c_args: test_c_args, include_directories: ls_inc) lm_objects = main.extract_objects(lease_manager_files) @@ -24,6 +29,7 @@ lm_test = executable('lease-manager-test', sources: lm_test_sources, objects: lm_objects, dependencies: [check_dep, fff_dep, dlmcommon_dep, drm_dep], + c_args: test_c_args, include_directories: ls_inc) test('DRM Lease manager - socket server test', ls_test, is_parallel: false) diff --git a/drm-lease-manager/test/test-drm-device.h b/drm-lease-manager/test/test-drm-device.h index e2e5f52..897e0f7 100644 --- a/drm-lease-manager/test/test-drm-device.h +++ b/drm-lease-manager/test/test-drm-device.h @@ -63,10 +63,14 @@ int create_lease(int fd, const uint32_t *objects, int num_objects, int flags, #define PLANE_ID(x) (test_device.plane_resources.planes[x]) #define LESSEE_ID(x) (test_device.leases.lessee_ids[x]) -#define CONNECTOR(cid, eid, encs, enc_cnt) \ - { \ - .connector_id = cid, .encoder_id = eid, \ - .count_encoders = enc_cnt, .encoders = encs, \ +#define CONNECTOR(cid, eid, encs, enc_cnt) \ + CONNECTOR_FULL(cid, eid, encs, enc_cnt, DRM_MODE_CONNECTOR_Unknown, cid) + +#define CONNECTOR_FULL(cid, eid, encs, enc_cnt, type, type_id) \ + { \ + .connector_id = cid, .encoder_id = eid, \ + .count_encoders = enc_cnt, .encoders = encs, \ + .connector_type = type, .connector_type_id = type_id, \ } #define ENCODER(eid, crtc, crtc_mask) \ -- cgit From 69acc5f3928f0578438cefdd69b39bc05bb0769b Mon Sep 17 00:00:00 2001 From: duerpei Date: Thu, 14 Apr 2022 10:01:20 +0800 Subject: Readme: Correct some spelling mistakes Bug-AGL:SPEC-4325 Signed-off-by: duerpei Change-Id: I3a315c9c17a1745554b08f277399564104f37fac --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 84af0a7..aa6cc2d 100644 --- a/README.md +++ b/README.md @@ -47,18 +47,18 @@ So, for example, a DRM lease for the first LVDS device on the device `/dev/dri/c ### Dynamic lease transfer When `drm-lease-manager` is started with the `-t` option, the -ownership of a leases resourses can be transfered from +ownership of a leases resources can be transferred from one client to another. This allows the ownership of the leased resources to be transferred without the display being closed and the screen blanking. -`drm-lease-manager` handles the timing of the tranfser and manages the +`drm-lease-manager` handles the timing of the transfer and manages the references to the DRM device, so that the last framebuffer of the old client stays on screen until the new client presents its first frame. The transition can be completed without direct communication between the old and new client applications, however, the client that the lease will be -transitioned *from* must be able to handle unexpected lease revokation. +transitioned *from* must be able to handle unexpected lease revocation. Once the lease is revoked, all DRM API calls referring to the DRM resources managed by the lease will fail with -ENOENT. The client should be able to gracefully handle this condition by, for example, -- cgit From e9e5cf1f67a45e4d409dc9e1caa6ce8151579c88 Mon Sep 17 00:00:00 2001 From: Damian Hobson-Garcia Date: Tue, 5 Apr 2022 12:11:38 +0900 Subject: Add configuration file loading and parsing Parse the lease configuration information from a configuration file. Each lease configuration takes a name and list of connectors to add to the lease. As long as one connector is found for a given configuration, the lease will be created. Bug-AGL: SPEC-3815 Change-Id: Iec4eaf37fba5db17a22e4945de10a06ac94063e4 Signed-off-by: Damian Hobson-Garcia --- drm-lease-manager/lease-config.c | 121 +++++++++++++++++++++++++++++ drm-lease-manager/lease-config.h | 19 +++++ drm-lease-manager/main.c | 18 ++++- drm-lease-manager/meson.build | 5 +- drm-lease-manager/test/lease-config-test.c | 102 ++++++++++++++++++++++++ drm-lease-manager/test/meson.build | 12 +++ meson.build | 1 + 7 files changed, 274 insertions(+), 4 deletions(-) create mode 100644 drm-lease-manager/lease-config.c create mode 100644 drm-lease-manager/lease-config.h create mode 100644 drm-lease-manager/test/lease-config-test.c diff --git a/drm-lease-manager/lease-config.c b/drm-lease-manager/lease-config.c new file mode 100644 index 0000000..abb7fc1 --- /dev/null +++ b/drm-lease-manager/lease-config.c @@ -0,0 +1,121 @@ +/* Copyright 2022 IGEL Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lease-config.h" +#include "log.h" +#include +#include +#include +#include +#include + +#define CONFIG_ERROR(x, ...) ERROR_LOG("%s: " x, filename, ##__VA_ARGS__) + +static bool populate_connector_names(struct lease_config *config, + toml_array_t *conns) +{ + int cnames = toml_array_nelem(conns); + config->connector_names = calloc(cnames, sizeof(char *)); + if (!config->connector_names) { + DEBUG_LOG("Memory allocation failed: %s\n", strerror(errno)); + return false; + } + + config->cnames = cnames; + + for (int i = 0; i < config->cnames; i++) { + toml_datum_t conn = toml_string_at(conns, i); + if (!conn.ok) { + return false; + } + config->connector_names[i] = conn.u.s; + } + return true; +} + +int parse_config(char *filename, struct lease_config **parsed_config) +{ + struct lease_config *config = NULL; + int nconfigs, i, ret = 0; + char parse_error[160]; + + FILE *fp = fopen(filename, "r"); + if (!fp) + return 0; + + toml_table_t *t_config = + toml_parse_file(fp, parse_error, sizeof parse_error); + if (!t_config) { + CONFIG_ERROR("configuration file parse error: %s\n", + parse_error); + fclose(fp); + return 0; + } + + toml_array_t *leases = toml_array_in(t_config, "lease"); + if (!leases) { + CONFIG_ERROR( + "Invalid config - cannot find any 'lease' configs"); + goto err; + } + nconfigs = toml_array_nelem(leases); + config = calloc(nconfigs, sizeof *config); + + if (!config) { + DEBUG_LOG("Memory allocation failed: %s\n", strerror(errno)); + goto err; + } + + for (i = 0; i < toml_array_nelem(leases); i++) { + toml_table_t *lease = toml_table_at(leases, i); + + toml_datum_t name = toml_string_in(lease, "name"); + if (!name.ok) { + CONFIG_ERROR("Invalid lease name in entry #%d\n", i); + goto err_free_config; + } + + config[i].lease_name = name.u.s; + + toml_array_t *conns = toml_array_in(lease, "connectors"); + if (conns && !populate_connector_names(&config[i], conns)) { + CONFIG_ERROR("Non string connector name in lease: %s\n", + config[i].lease_name); + goto err_free_config; + } + } + + *parsed_config = config; + ret = nconfigs; +err: + toml_free(t_config); + fclose(fp); + return ret; +err_free_config: + release_config(i, config); + goto err; +} + +void release_config(int num_leases, struct lease_config *config) +{ + for (int i = 0; i < num_leases; i++) { + struct lease_config *c = &config[i]; + free(c->lease_name); + for (int j = 0; j < c->cnames; j++) + free(c->connector_names[j]); + free(c->connector_names); + } + free(config); +} diff --git a/drm-lease-manager/lease-config.h b/drm-lease-manager/lease-config.h new file mode 100644 index 0000000..0760a99 --- /dev/null +++ b/drm-lease-manager/lease-config.h @@ -0,0 +1,19 @@ +/* Copyright 2022 IGEL Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "drm-lease.h" + +int parse_config(char *filename, struct lease_config **parsed_config); +void release_config(int num_leasess, struct lease_config *config); diff --git a/drm-lease-manager/main.c b/drm-lease-manager/main.c index 2927253..ff69e75 100644 --- a/drm-lease-manager/main.c +++ b/drm-lease-manager/main.c @@ -13,6 +13,7 @@ * limitations under the License. */ +#include "lease-config.h" #include "lease-manager.h" #include "lease-server.h" #include "log.h" @@ -27,24 +28,28 @@ static void usage(const char *progname) printf("Usage: %s [OPTIONS] []\n\n" "Options:\n" "-h, --help \tPrint this help\n" + "-c, --config \t path to configuration file (default " + "/etc/drm-lease-manager.toml)\n" "-v, --verbose \tEnable verbose debug messages\n" "-t, --lease-transfer \tAllow lease transfter to new clients\n" "-k, --keep-on-crash \tDon't close lease on client crash\n", progname); } -const char *opts = "vtkh"; +const char *opts = "vtkhc:"; const struct option options[] = { {"help", no_argument, NULL, 'h'}, {"verbose", no_argument, NULL, 'v'}, {"lease-transfer", no_argument, NULL, 't'}, {"keep-on-crash", no_argument, NULL, 'k'}, + {"config", required_argument, NULL, 'c'}, {NULL, 0, NULL, 0}, }; int main(int argc, char **argv) { char *device = "/dev/dri/card0"; + char *config_file = "/etc/drm-lease-manager.toml"; bool debug_log = false; bool can_transfer_leases = false; @@ -63,6 +68,9 @@ int main(int argc, char **argv) case 'k': keep_on_crash = true; break; + case 'c': + config_file = optarg; + break; case 'h': ret = EXIT_SUCCESS; /* fall through */ @@ -77,7 +85,12 @@ int main(int argc, char **argv) dlm_log_enable_debug(debug_log); - struct lm *lm = lm_create(device); + struct lease_config *lease_configs = NULL; + int num_configs = parse_config(config_file, &lease_configs); + + struct lm *lm = + lm_create_with_config(device, num_configs, lease_configs); + if (!lm) { ERROR_LOG("DRM Lease initialization failed\n"); return EXIT_FAILURE; @@ -145,5 +158,6 @@ int main(int argc, char **argv) done: ls_destroy(ls); lm_destroy(lm); + release_config(num_configs, lease_configs); return EXIT_FAILURE; } diff --git a/drm-lease-manager/meson.build b/drm-lease-manager/meson.build index 7157f01..4732283 100644 --- a/drm-lease-manager/meson.build +++ b/drm-lease-manager/meson.build @@ -1,9 +1,10 @@ lease_manager_files = files('lease-manager.c') lease_server_files = files('lease-server.c') +lease_config_files = files('lease-config.c') main = executable('drm-lease-manager', - [ 'main.c', lease_manager_files, lease_server_files ], - dependencies: [ drm_dep, dlmcommon_dep, thread_dep ], + [ 'main.c', lease_manager_files, lease_server_files, lease_config_files ], + dependencies: [ drm_dep, dlmcommon_dep, thread_dep, toml_dep ], install: true, ) diff --git a/drm-lease-manager/test/lease-config-test.c b/drm-lease-manager/test/lease-config-test.c new file mode 100644 index 0000000..fa5edcd --- /dev/null +++ b/drm-lease-manager/test/lease-config-test.c @@ -0,0 +1,102 @@ +/* Copyright 2022 IGEL Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lease-config.h" +#include +#include +#include +#include + +#define CONFIG_FILE_TEMPLATE "/tmp/dlmconfig_tmpXXXXXX" +int config_fd; +char config_file[] = CONFIG_FILE_TEMPLATE; + +static void test_setup(void) +{ + strcpy(config_file, CONFIG_FILE_TEMPLATE); + config_fd = mkstemp(config_file); + ck_assert_int_ge(config_fd, 0); +} + +static void test_shutdown(void) +{ + close(config_fd); + unlink(config_file); +} + +/* parse config file test */ +/* Test details: Parse a config file + * Expected results: a config with the expected results + */ + +START_TEST(parse_leases) +{ + ck_assert_ptr_ne(config_file, NULL); + + char test_data[] = "[[lease]]\n" + "name = \"lease 1\"\n" + "connectors = [\"1\", \"b\",\"gamma\" ]\n" + "[[lease]]\n" + "name = \"lease 2\"\n" + "connectors = [\"connector 3\"]\n"; + + write(config_fd, test_data, sizeof(test_data)); + + struct lease_config *config = NULL; + int nconfigs = parse_config(config_file, &config); + + ck_assert_int_eq(nconfigs, 2); + ck_assert_ptr_ne(config, NULL); + + ck_assert_str_eq(config[0].lease_name, "lease 1"); + ck_assert_int_eq(config[0].cnames, 3); + ck_assert_str_eq(config[0].connector_names[0], "1"); + ck_assert_str_eq(config[0].connector_names[1], "b"); + ck_assert_str_eq(config[0].connector_names[2], "gamma"); + + ck_assert_str_eq(config[1].lease_name, "lease 2"); + ck_assert_int_eq(config[1].cnames, 1); + ck_assert_str_eq(config[1].connector_names[0], "connector 3"); + + release_config(nconfigs, config); +} +END_TEST + +static void add_parse_tests(Suite *s) +{ + TCase *tc = tcase_create("Config file parsing tests"); + + tcase_add_checked_fixture(tc, test_setup, test_shutdown); + + tcase_add_test(tc, parse_leases); + suite_add_tcase(s, tc); +} + +int main(void) +{ + int number_failed; + Suite *s; + SRunner *sr; + + s = suite_create("DLM lease manager tests"); + + add_parse_tests(s); + + sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/drm-lease-manager/test/meson.build b/drm-lease-manager/test/meson.build index bb97274..8d5c06f 100644 --- a/drm-lease-manager/test/meson.build +++ b/drm-lease-manager/test/meson.build @@ -32,5 +32,17 @@ lm_test = executable('lease-manager-test', c_args: test_c_args, include_directories: ls_inc) +lc_objects = main.extract_objects(lease_config_files) +lc_test_sources = [ + 'lease-config-test.c' +] + +lc_test = executable('lease-config-test', + sources: lc_test_sources, + objects: lc_objects, + dependencies: [check_dep, dlmcommon_dep, toml_dep], + include_directories: ls_inc) + test('DRM Lease manager - socket server test', ls_test, is_parallel: false) test('DRM Lease manager - DRM interface test', lm_test) +test('DRM Lease manager - config parse test', lc_test) diff --git a/meson.build b/meson.build index 7f8adf5..c2c88a6 100644 --- a/meson.build +++ b/meson.build @@ -35,6 +35,7 @@ configuration_inc = include_directories('.') drm_dep = dependency('libdrm', version: '>= 2.4.89') thread_dep = dependency('threads') +toml_dep = dependency('libtoml') enable_tests = get_option('enable-tests') -- cgit From 17bf719d3b141142c6fa908485dec4ca5872fa83 Mon Sep 17 00:00:00 2001 From: Damian Hobson-Garcia Date: Tue, 5 Apr 2022 16:49:22 +0900 Subject: Update README to describe configuration file format Bug-AGL: SPEC-3815 Change-Id: I61d0fdea053ef1bd4f6b78838590636b6ce0ca6c Signed-off-by: Damian Hobson-Garcia --- README.md | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index aa6cc2d..f9a7650 100644 --- a/README.md +++ b/README.md @@ -24,18 +24,33 @@ The basic build procedure is as follows: `` can be any directory name, but `build` is commonly used. -## Running +## Configuration -Once installed, running the following command will start the DRM Lease Manager daemon +The drm-lease-manager configuration file allows the user to specify the mapping +of DRM connectors to DRM leases. The location of the configuration file can +be specified with the `--config` command line option. - drm-lease-manager [] +The configuration file consists of a list of lease definitions, containing a name +of the lease and a list of the included connector names. -If no DRM device is specified, `/dev/dri/card0` will be used. -More detailed options can be displayed by specifying the `-h` flag. +Each list entry is of the following form: -### Lease naming +```toml +[[lease]] +name="My lease" +connectors=["connector 1", "connector 2"] +``` +* Note: quotes around all string values are mandatory. + +This will create a lease named `My lease` and add the two connectors `connector 1` and +`connector 2` to the lease. +If there is no connector with either of the names exists on the system, that name +will be omitted from the lease. -One DRM lease will be created for each connector on the DRM device (up to the number of available CRTCs). +### Default configuration + +If no configuration file is specified one DRM lease will be created for each connector +on the DRM device (up to the number of available CRTCs). The names of the DRM leases will have the following pattern: @@ -44,6 +59,15 @@ The names of the DRM leases will have the following pattern: So, for example, a DRM lease for the first LVDS device on the device `/dev/dri/card0` would be named `card0-LVDS-1`. +## Running + +Once installed, running the following command will start the DRM Lease Manager daemon + + drm-lease-manager [] + +If no DRM device is specified, `/dev/dri/card0` will be used. +More detailed options can be displayed by specifying the `-h` flag. + ### Dynamic lease transfer When `drm-lease-manager` is started with the `-t` option, the -- cgit From 6a12fcc3821e913ca799ff8981d9415d0a251836 Mon Sep 17 00:00:00 2001 From: Damian Hobson-Garcia Date: Wed, 6 Apr 2022 18:11:38 +0900 Subject: Default to first modesettable DRM device When no DRM device is specified on the command line, try all available DRM devices until an available modesettable device is found. Bug-AGL: SPEC-3815 Change-Id: I72343558fcda755a63aee549767ccc8c00c06724 Signed-off-by: Damian Hobson-Garcia --- README.md | 4 ++-- drm-lease-manager/lease-manager.c | 29 +++++++++++++++++++++++++++-- drm-lease-manager/main.c | 2 +- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f9a7650..458cdde 100644 --- a/README.md +++ b/README.md @@ -65,8 +65,8 @@ Once installed, running the following command will start the DRM Lease Manager d drm-lease-manager [] -If no DRM device is specified, `/dev/dri/card0` will be used. -More detailed options can be displayed by specifying the `-h` flag. +If no DRM device is specified, the first available device capabale of modesetting will +be used. More detailed options can be displayed by specifying the `-h` flag. ### Dynamic lease transfer diff --git a/drm-lease-manager/lease-manager.c b/drm-lease-manager/lease-manager.c index b339037..291594c 100644 --- a/drm-lease-manager/lease-manager.c +++ b/drm-lease-manager/lease-manager.c @@ -515,6 +515,29 @@ err: return NULL; } +static struct lm *drm_find_drm_device(const char *device) +{ + drmDevicePtr devices[64]; + int ndevs; + struct lm *lm = NULL; + + if (device) + return drm_device_get_resources(device); + + ndevs = drmGetDevices2(0, devices, 64); + + for (int i = 0; i < ndevs; i++) { + lm = drm_device_get_resources( + devices[i]->nodes[DRM_NODE_PRIMARY]); + if (lm) + break; + } + + drmFreeDevices(devices, ndevs); + + return lm; +} + static int lm_create_leases(struct lm *lm, int num_leases, const struct lease_config *configs) { @@ -544,10 +567,12 @@ struct lm *lm_create_with_config(const char *device, int num_leases, struct lease_config *configs) { struct lease_config *default_configs = NULL; - struct lm *lm = drm_device_get_resources(device); + struct lm *lm = drm_find_drm_device(device); - if (!lm) + if (!lm) { + ERROR_LOG("No available DRM device found\n"); return NULL; + } if (configs == NULL || num_leases == 0) { num_leases = create_default_lease_configs(lm, &default_configs); diff --git a/drm-lease-manager/main.c b/drm-lease-manager/main.c index ff69e75..b4ad379 100644 --- a/drm-lease-manager/main.c +++ b/drm-lease-manager/main.c @@ -48,7 +48,7 @@ const struct option options[] = { int main(int argc, char **argv) { - char *device = "/dev/dri/card0"; + char *device = NULL; char *config_file = "/etc/drm-lease-manager.toml"; bool debug_log = false; -- cgit From 84bd108e702b753bc1f7b232c94baa5b84295b5f Mon Sep 17 00:00:00 2001 From: Damian Hobson-Garcia Date: Thu, 14 Apr 2022 15:22:07 +0900 Subject: Refactor connector in lease config A connector within a lease configuration can have more attributes than just a name. Refactor it into a connector configuation that can store additional properties. Bug-AGL: SPEC-3815 Change-Id: Ied4c767bba914eb64b9e82c600e10162d0232c65 Signed-off-by: Damian Hobson-Garcia --- drm-lease-manager/drm-lease.h | 8 ++++++-- drm-lease-manager/lease-config.c | 28 +++++++++++++++------------- drm-lease-manager/lease-manager.c | 7 ++++--- drm-lease-manager/test/lease-config-test.c | 12 ++++++------ drm-lease-manager/test/lease-manager-test.c | 8 ++++++-- 5 files changed, 37 insertions(+), 26 deletions(-) diff --git a/drm-lease-manager/drm-lease.h b/drm-lease-manager/drm-lease.h index 76f0bd7..2de4fa4 100644 --- a/drm-lease-manager/drm-lease.h +++ b/drm-lease-manager/drm-lease.h @@ -22,14 +22,18 @@ struct lease_handle { void *user_data; }; +struct connector_config { + char *name; +}; + struct lease_config { char *lease_name; int ncids; uint32_t *connector_ids; - int cnames; - char **connector_names; + int nconnectors; + struct connector_config *connectors; }; #endif diff --git a/drm-lease-manager/lease-config.c b/drm-lease-manager/lease-config.c index abb7fc1..e246445 100644 --- a/drm-lease-manager/lease-config.c +++ b/drm-lease-manager/lease-config.c @@ -23,24 +23,26 @@ #define CONFIG_ERROR(x, ...) ERROR_LOG("%s: " x, filename, ##__VA_ARGS__) -static bool populate_connector_names(struct lease_config *config, - toml_array_t *conns) +static bool populate_connector_config(struct lease_config *config, + toml_array_t *conns) { - int cnames = toml_array_nelem(conns); - config->connector_names = calloc(cnames, sizeof(char *)); - if (!config->connector_names) { + int nconnectors = toml_array_nelem(conns); + config->connectors = calloc(nconnectors, sizeof(*config->connectors)); + if (!config->connectors) { DEBUG_LOG("Memory allocation failed: %s\n", strerror(errno)); return false; } - config->cnames = cnames; + config->nconnectors = nconnectors; - for (int i = 0; i < config->cnames; i++) { + for (int i = 0; i < config->nconnectors; i++) { toml_datum_t conn = toml_string_at(conns, i); if (!conn.ok) { + ERROR_LOG("Invalid connector in lease %s: idx:%d\n", + config->lease_name, i); return false; } - config->connector_names[i] = conn.u.s; + config->connectors[i].name = conn.u.s; } return true; } @@ -90,8 +92,8 @@ int parse_config(char *filename, struct lease_config **parsed_config) config[i].lease_name = name.u.s; toml_array_t *conns = toml_array_in(lease, "connectors"); - if (conns && !populate_connector_names(&config[i], conns)) { - CONFIG_ERROR("Non string connector name in lease: %s\n", + if (conns && !populate_connector_config(&config[i], conns)) { + CONFIG_ERROR("Error configuring lease: %s\n", config[i].lease_name); goto err_free_config; } @@ -113,9 +115,9 @@ void release_config(int num_leases, struct lease_config *config) for (int i = 0; i < num_leases; i++) { struct lease_config *c = &config[i]; free(c->lease_name); - for (int j = 0; j < c->cnames; j++) - free(c->connector_names[j]); - free(c->connector_names); + for (int j = 0; j < c->nconnectors; j++) + free(c->connectors[j].name); + free(c->connectors); } free(config); } diff --git a/drm-lease-manager/lease-manager.c b/drm-lease-manager/lease-manager.c index 291594c..177a241 100644 --- a/drm-lease-manager/lease-manager.c +++ b/drm-lease-manager/lease-manager.c @@ -343,7 +343,8 @@ static struct lease *lease_create(struct lm *lm, goto err; } - int nconnectors = config->cnames > 0 ? config->cnames : config->ncids; + int nconnectors = + config->nconnectors > 0 ? config->nconnectors : config->ncids; int nobjects = lm->drm_plane_resource->count_planes + nconnectors * DRM_OBJECTS_PER_CONNECTOR; @@ -356,8 +357,8 @@ static struct lease *lease_create(struct lm *lm, for (int i = 0; i < nconnectors; i++) { uint32_t cid; - if (config->cnames > 0) { - char *connector_name = config->connector_names[i]; + if (config->nconnectors > 0) { + char *connector_name = config->connectors[i].name; if (!drm_find_connector(lm, connector_name, &cid)) { WARN_LOG("Lease: %s, " diff --git a/drm-lease-manager/test/lease-config-test.c b/drm-lease-manager/test/lease-config-test.c index fa5edcd..65bd32a 100644 --- a/drm-lease-manager/test/lease-config-test.c +++ b/drm-lease-manager/test/lease-config-test.c @@ -61,14 +61,14 @@ START_TEST(parse_leases) ck_assert_ptr_ne(config, NULL); ck_assert_str_eq(config[0].lease_name, "lease 1"); - ck_assert_int_eq(config[0].cnames, 3); - ck_assert_str_eq(config[0].connector_names[0], "1"); - ck_assert_str_eq(config[0].connector_names[1], "b"); - ck_assert_str_eq(config[0].connector_names[2], "gamma"); + ck_assert_int_eq(config[0].nconnectors, 3); + ck_assert_str_eq(config[0].connectors[0].name, "1"); + ck_assert_str_eq(config[0].connectors[1].name, "b"); + ck_assert_str_eq(config[0].connectors[2].name, "gamma"); ck_assert_str_eq(config[1].lease_name, "lease 2"); - ck_assert_int_eq(config[1].cnames, 1); - ck_assert_str_eq(config[1].connector_names[0], "connector 3"); + ck_assert_int_eq(config[1].nconnectors, 1); + ck_assert_str_eq(config[1].connectors[0].name, "connector 3"); release_config(nconfigs, config); } diff --git a/drm-lease-manager/test/lease-manager-test.c b/drm-lease-manager/test/lease-manager-test.c index f6524ab..b32cd05 100644 --- a/drm-lease-manager/test/lease-manager-test.c +++ b/drm-lease-manager/test/lease-manager-test.c @@ -508,8 +508,12 @@ START_TEST(named_connector_config) struct lease_config lconfig = { .lease_name = "Lease Config Test 1", - .cnames = 2, - .connector_names = (char *[]){"HDMI-A-1", "VGA-3"}, + .nconnectors = 2, + .connectors = + (struct connector_config[]){ + {.name = "HDMI-A-1"}, + {.name = "VGA-3"}, + }, }; struct lease_handle **handles = create_leases(lease_cnt, &lconfig); -- cgit From 5c27165cdcfb28c8b2eccc139802fa0dd6403776 Mon Sep 17 00:00:00 2001 From: Damian Hobson-Garcia Date: Thu, 14 Apr 2022 15:24:11 +0900 Subject: Add 'optional' property to connector configuration All connectors will default to mandatory. i.e. if any specified connector is in the lease configuration is not available, that lease will not be created. Setting a connector as 'optional' lets the lease creation succeed even if the connector is not physically present on the system. Failing to create a lease does not affect the creation of other leases. The drm-lease-manager daemon will run as long as one lease is successfully created. Bug-AGL: SPEC-3815 Change-Id: I5edf8a97a2a3589e8eb5368c0a5b13adb4cb5c9b Signed-off-by: Damian Hobson-Garcia --- drm-lease-manager/drm-lease.h | 2 ++ drm-lease-manager/lease-config.c | 17 +++++++++++++++-- drm-lease-manager/lease-manager.c | 22 +++++++++++++++++++--- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/drm-lease-manager/drm-lease.h b/drm-lease-manager/drm-lease.h index 2de4fa4..84fa942 100644 --- a/drm-lease-manager/drm-lease.h +++ b/drm-lease-manager/drm-lease.h @@ -15,6 +15,7 @@ #ifndef DRM_LEASE_H #define DRM_LEASE_H +#include #include struct lease_handle { @@ -24,6 +25,7 @@ struct lease_handle { struct connector_config { char *name; + bool optional; }; struct lease_config { diff --git a/drm-lease-manager/lease-config.c b/drm-lease-manager/lease-config.c index e246445..b3f35a1 100644 --- a/drm-lease-manager/lease-config.c +++ b/drm-lease-manager/lease-config.c @@ -24,6 +24,7 @@ #define CONFIG_ERROR(x, ...) ERROR_LOG("%s: " x, filename, ##__VA_ARGS__) static bool populate_connector_config(struct lease_config *config, + toml_table_t *global_table, toml_array_t *conns) { int nconnectors = toml_array_nelem(conns); @@ -36,13 +37,24 @@ static bool populate_connector_config(struct lease_config *config, config->nconnectors = nconnectors; for (int i = 0; i < config->nconnectors; i++) { + struct connector_config *conn_config = &config->connectors[i]; toml_datum_t conn = toml_string_at(conns, i); if (!conn.ok) { ERROR_LOG("Invalid connector in lease %s: idx:%d\n", config->lease_name, i); return false; } - config->connectors[i].name = conn.u.s; + conn_config->name = conn.u.s; + + toml_table_t *conn_config_data = + toml_table_in(global_table, conn.u.s); + if (!conn_config_data) + continue; + + toml_datum_t optional = + toml_bool_in(conn_config_data, "optional"); + if (optional.ok) + config->connectors[i].optional = optional.u.b; } return true; } @@ -92,7 +104,8 @@ int parse_config(char *filename, struct lease_config **parsed_config) config[i].lease_name = name.u.s; toml_array_t *conns = toml_array_in(lease, "connectors"); - if (conns && !populate_connector_config(&config[i], conns)) { + if (conns && + !populate_connector_config(&config[i], t_config, conns)) { CONFIG_ERROR("Error configuring lease: %s\n", config[i].lease_name); goto err_free_config; diff --git a/drm-lease-manager/lease-manager.c b/drm-lease-manager/lease-manager.c index 177a241..3834631 100644 --- a/drm-lease-manager/lease-manager.c +++ b/drm-lease-manager/lease-manager.c @@ -356,11 +356,27 @@ static struct lease *lease_create(struct lm *lm, for (int i = 0; i < nconnectors; i++) { uint32_t cid; + struct connector_config *con_config = NULL; - if (config->nconnectors > 0) { - char *connector_name = config->connectors[i].name; + if (config->nconnectors > 0) + con_config = &config->connectors[i]; - if (!drm_find_connector(lm, connector_name, &cid)) { + if (con_config) { + char *connector_name = con_config->name; + bool optional = con_config->optional; + + bool found = + drm_find_connector(lm, connector_name, &cid); + + bool missing_mandatory = !found && !optional; + bool missing_optional = !found && optional; + + if (missing_mandatory) { + ERROR_LOG("Lease: %s, " + "mandatory connector %s not found\n", + config->lease_name, connector_name); + goto err; + } else if (missing_optional) { WARN_LOG("Lease: %s, " "unknown DRM connector: %s\n", config->lease_name, connector_name); -- cgit From 53f4fe700dee88cc9840a91f2f297aacf05e08d4 Mon Sep 17 00:00:00 2001 From: Damian Hobson-Garcia Date: Fri, 8 Apr 2022 10:40:03 +0900 Subject: Add plane setting to connector configuration Provide a setting to override the default DRM plane alloction for each connector in a lease. DRM planes that are compatible with multiple CRTCs/ connectors can now be assigned to a lease by explicity setting the connector that they belong to in the configuration file. This can also be used to restrict the planes that are available to a given connector. Bug-AGL: SPEC-3815 Change-Id: If4168fc3081213c4ed1df09755cadf042c68d9a3 Signed-off-by: Damian Hobson-Garcia --- drm-lease-manager/drm-lease.h | 2 + drm-lease-manager/lease-config.c | 32 ++++++++++++- drm-lease-manager/lease-manager.c | 54 ++++++++++++++++++---- drm-lease-manager/test/lease-config-test.c | 38 +++++++++++++++ drm-lease-manager/test/lease-manager-test.c | 71 +++++++++++++++++++++++++++++ 5 files changed, 188 insertions(+), 9 deletions(-) diff --git a/drm-lease-manager/drm-lease.h b/drm-lease-manager/drm-lease.h index 84fa942..5670fa8 100644 --- a/drm-lease-manager/drm-lease.h +++ b/drm-lease-manager/drm-lease.h @@ -26,6 +26,8 @@ struct lease_handle { struct connector_config { char *name; bool optional; + int nplanes; + uint32_t *planes; }; struct lease_config { diff --git a/drm-lease-manager/lease-config.c b/drm-lease-manager/lease-config.c index b3f35a1..aaba6b6 100644 --- a/drm-lease-manager/lease-config.c +++ b/drm-lease-manager/lease-config.c @@ -23,6 +23,26 @@ #define CONFIG_ERROR(x, ...) ERROR_LOG("%s: " x, filename, ##__VA_ARGS__) +static bool populate_connector_planes(struct connector_config *config, + toml_array_t *planes) +{ + config->nplanes = toml_array_nelem(planes); + config->planes = calloc(config->nplanes, sizeof(uint32_t)); + if (!config->planes) { + DEBUG_LOG("Memory allocation failed: %s\n", strerror(errno)); + return false; + } + + for (int j = 0; j < config->nplanes; j++) { + toml_datum_t plane = toml_int_at(planes, j); + if (!plane.ok) { + return false; + } + config->planes[j] = plane.u.i; + } + return true; +} + static bool populate_connector_config(struct lease_config *config, toml_table_t *global_table, toml_array_t *conns) @@ -55,6 +75,14 @@ static bool populate_connector_config(struct lease_config *config, toml_bool_in(conn_config_data, "optional"); if (optional.ok) config->connectors[i].optional = optional.u.b; + + toml_array_t *planes = + toml_array_in(conn_config_data, "planes"); + if (planes && !populate_connector_planes(conn_config, planes)) { + ERROR_LOG("Invalid plane id for connector: %s\n", + conn_config->name); + return false; + } } return true; } @@ -128,8 +156,10 @@ void release_config(int num_leases, struct lease_config *config) for (int i = 0; i < num_leases; i++) { struct lease_config *c = &config[i]; free(c->lease_name); - for (int j = 0; j < c->nconnectors; j++) + for (int j = 0; j < c->nconnectors; j++) { free(c->connectors[j].name); + free(c->connectors[j].planes); + } free(c->connectors); } free(config); diff --git a/drm-lease-manager/lease-manager.c b/drm-lease-manager/lease-manager.c index 3834631..885ca29 100644 --- a/drm-lease-manager/lease-manager.c +++ b/drm-lease-manager/lease-manager.c @@ -216,17 +216,48 @@ static bool drm_find_connector(struct lm *lm, char *name, uint32_t *id) return false; } -static bool lease_add_planes(struct lm *lm, struct lease *lease, int crtc_index) +static void config_get_planes(struct lm *lm, + const struct connector_config *config, + int *nplanes, uint32_t **planes) { - for (uint32_t i = 0; i < lm->drm_plane_resource->count_planes; i++) { - uint32_t plane_id = lm->drm_plane_resource->planes[i]; + if (config && config->planes) { + *nplanes = config->nplanes; + *planes = config->planes; + } else { + *nplanes = (int)lm->drm_plane_resource->count_planes; + *planes = lm->drm_plane_resource->planes; + } +} + +static bool lease_add_planes(struct lm *lm, struct lease *lease, + uint32_t crtc_index, + const struct connector_config *con_config) +{ + int nplanes; + uint32_t *planes; + uint32_t crtc_mask = (1 << crtc_index); + + /* Only allow shared planes when plane list is explicitly set */ + bool allow_shared = con_config && con_config->planes; + + config_get_planes(lm, con_config, &nplanes, &planes); + + for (int i = 0; i < nplanes; i++) { + uint32_t plane_id = planes[i]; drmModePlanePtr plane = drmModeGetPlane(lm->drm_fd, plane_id); - assert(plane); + if (!plane) { + ERROR_LOG( + "Unknown plane id %d configured in lease: %s\n", + plane_id, lease->base.name); + return false; + } - // Exclude planes that can be used with multiple CRTCs for now - if (plane->possible_crtcs == (1u << crtc_index)) { - lease->object_ids[lease->nobject_ids++] = plane_id; + if (plane->possible_crtcs & crtc_mask) { + bool shared_plane = plane->possible_crtcs != crtc_mask; + if (allow_shared || !shared_plane) + lease->object_ids[lease->nobject_ids++] = + plane_id; } drmModeFreePlane(plane); } @@ -404,7 +435,7 @@ static struct lease *lease_create(struct lm *lm, goto err; } - if (!lease_add_planes(lm, lease, crtc_index)) + if (!lease_add_planes(lm, lease, crtc_index, con_config)) goto err; uint32_t crtc_id = lm->drm_resource->crtcs[crtc_index]; @@ -487,6 +518,13 @@ static struct lm *drm_device_get_resources(const char *device) goto err; } + /* Enable universal planes so that ALL planes, even primary and cursor + * planes can be assigned from lease configurations. */ + if (drmSetClientCap(lm->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1)) { + DEBUG_LOG("drmSetClientCap failed\n"); + goto err; + } + lm->drm_resource = drmModeGetResources(lm->drm_fd); if (!lm->drm_resource) { ERROR_LOG("Invalid DRM device(%s)\n", device); diff --git a/drm-lease-manager/test/lease-config-test.c b/drm-lease-manager/test/lease-config-test.c index 65bd32a..0dc171f 100644 --- a/drm-lease-manager/test/lease-config-test.c +++ b/drm-lease-manager/test/lease-config-test.c @@ -74,6 +74,43 @@ START_TEST(parse_leases) } END_TEST +START_TEST(connector_config) +{ + ck_assert_ptr_ne(config_file, NULL); + + char test_data[] = "[[lease]]\n" + "name = \"lease 1\"\n" + "connectors = [\"1\", \"b\",\"gamma\" ]\n" + "[b]\n" + "optional = true\n" + "planes = [1, 4, 3]\n"; + + write(config_fd, test_data, sizeof(test_data)); + + struct lease_config *config = NULL; + int nconfigs = parse_config(config_file, &config); + + ck_assert_int_eq(nconfigs, 1); + ck_assert_ptr_ne(config, NULL); + + ck_assert_str_eq(config[0].lease_name, "lease 1"); + ck_assert_int_eq(config[0].nconnectors, 3); + ck_assert_str_eq(config[0].connectors[0].name, "1"); + ck_assert_str_eq(config[0].connectors[1].name, "b"); + ck_assert_str_eq(config[0].connectors[2].name, "gamma"); + + ck_assert(!config[0].connectors[0].optional); + ck_assert(config[0].connectors[1].optional); + ck_assert(!config[0].connectors[2].optional); + + ck_assert_int_eq(config[0].connectors[1].nplanes, 3); + ck_assert_int_eq(config[0].connectors[1].planes[0], 1); + ck_assert_int_eq(config[0].connectors[1].planes[1], 4); + ck_assert_int_eq(config[0].connectors[1].planes[2], 3); + + release_config(nconfigs, config); +} +END_TEST static void add_parse_tests(Suite *s) { TCase *tc = tcase_create("Config file parsing tests"); @@ -81,6 +118,7 @@ static void add_parse_tests(Suite *s) tcase_add_checked_fixture(tc, test_setup, test_shutdown); tcase_add_test(tc, parse_leases); + tcase_add_test(tc, connector_config); suite_add_tcase(s, tc); } diff --git a/drm-lease-manager/test/lease-manager-test.c b/drm-lease-manager/test/lease-manager-test.c index b32cd05..fa87815 100644 --- a/drm-lease-manager/test/lease-manager-test.c +++ b/drm-lease-manager/test/lease-manager-test.c @@ -61,6 +61,7 @@ FAKE_VOID_FUNC(drmModeFreeEncoder, drmModeEncoderPtr); FAKE_VALUE_FUNC(int, drmModeCreateLease, int, const uint32_t *, int, int, uint32_t *); FAKE_VALUE_FUNC(int, drmModeRevokeLease, int, uint32_t); +FAKE_VALUE_FUNC(int, drmSetClientCap, int, uint64_t, uint64_t); /************** Test fixutre functions *************************/ struct lm *g_lm = NULL; @@ -90,6 +91,8 @@ static void test_setup(void) drmModeGetEncoder_fake.custom_fake = get_encoder; drmModeCreateLease_fake.custom_fake = create_lease; + drmSetClientCap_fake.return_val = 0; + ck_assert_msg(g_lm == NULL, "Lease manager context not clear at start of test"); } @@ -524,6 +527,73 @@ START_TEST(named_connector_config) } END_TEST +/* config plane sharing */ +/* Test details: Add overlay planes to leases. Some planes are shared between + * multiple CRTCs. These planes are explicitly assigned to a + * connector. Expected results: The leases contain all of the unique planes for + * each CRTC. Shared planes are also included as defined by the lease + * configuration. + */ +START_TEST(config_plane_sharing) +{ + + int out_cnt = 2, plane_cnt = 3, lease_cnt = 2; + + ck_assert_int_eq( + setup_drm_test_device(out_cnt, out_cnt, out_cnt, plane_cnt), true); + + drmModeConnector connectors[] = { + CONNECTOR_FULL(CONNECTOR_ID(0), ENCODER_ID(0), &ENCODER_ID(0), 1, + DRM_MODE_CONNECTOR_HDMIA, 1), + CONNECTOR_FULL(CONNECTOR_ID(1), ENCODER_ID(1), &ENCODER_ID(1), 1, + DRM_MODE_CONNECTOR_VGA, 3), + }; + + drmModeEncoder encoders[] = { + ENCODER(ENCODER_ID(0), CRTC_ID(0), 0x1), + ENCODER(ENCODER_ID(1), CRTC_ID(1), 0x2), + }; + + drmModePlane planes[] = { + PLANE(PLANE_ID(0), 0x2), + PLANE(PLANE_ID(1), 0x1), + PLANE(PLANE_ID(2), 0x3), + }; + + setup_test_device_layout(connectors, encoders, planes); + + struct lease_config lconfig[] = { + [0] = + { + .lease_name = "Lease Config Test 1", + .nconnectors = 1, + .connectors = + (struct connector_config[]){ + {.name = "HDMI-A-1", + .nplanes = 2, + .planes = (uint32_t[]){PLANE_ID(1), PLANE_ID(2)}}, + }, + }, + [1] = + { + .lease_name = "Lease Config Test 2", + .nconnectors = 1, + .connectors = + (struct connector_config[]){ + {.name = "VGA-3"}, + }, + }, + }; + + struct lease_handle **handles = create_leases(lease_cnt, lconfig); + + CHECK_LEASE_OBJECTS(handles[0], PLANE_ID(1), PLANE_ID(2), CRTC_ID(0), + CONNECTOR_ID(0)); + CHECK_LEASE_OBJECTS(handles[1], PLANE_ID(0), CRTC_ID(1), + CONNECTOR_ID(1)); +} +END_TEST + static void add_lease_config_tests(Suite *s) { TCase *tc = tcase_create("Lease configuration"); @@ -533,6 +603,7 @@ static void add_lease_config_tests(Suite *s) tcase_add_test(tc, multiple_connector_lease); tcase_add_test(tc, single_failed_lease); tcase_add_test(tc, named_connector_config); + tcase_add_test(tc, config_plane_sharing); suite_add_tcase(s, tc); } -- cgit