Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/vkms: Allow to configure multiple connectors

Add a list of connectors to vkms_config and helper functions to add and
remove as many connectors as wanted.

For backwards compatibility, add one enabled connector to the default
configuration.

A future patch will allow to attach connectors and encoders, but for the
moment there are no changes in the way the output is configured.

Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>
Co-developed-by: Louis Chauvet <louis.chauvet@bootlin.com>
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
Signed-off-by: José Expósito <jose.exposito89@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20250218101214.5790-14-jose.exposito89@gmail.com
Signed-off-by: Maxime Ripard <mripard@kernel.org>

authored by

José Expósito and committed by
Maxime Ripard
da38c720 b8776fc9

+205
+1
.clang-format
··· 690 690 - 'v4l2_m2m_for_each_src_buf' 691 691 - 'v4l2_m2m_for_each_src_buf_safe' 692 692 - 'virtio_device_for_each_vq' 693 + - 'vkms_config_for_each_connector' 693 694 - 'vkms_config_for_each_crtc' 694 695 - 'vkms_config_for_each_encoder' 695 696 - 'vkms_config_for_each_plane'
+95
drivers/gpu/drm/vkms/tests/vkms_config_test.c
··· 28 28 return count; 29 29 } 30 30 31 + static size_t vkms_config_get_num_connectors(struct vkms_config *config) 32 + { 33 + struct vkms_config_connector *connector_cfg; 34 + size_t count = 0; 35 + 36 + vkms_config_for_each_connector(config, connector_cfg) 37 + count++; 38 + 39 + return count; 40 + } 41 + 31 42 static struct vkms_config_plane *get_first_plane(struct vkms_config *config) 32 43 { 33 44 struct vkms_config_plane *plane_cfg; ··· 69 58 return NULL; 70 59 } 71 60 61 + static struct vkms_config_connector *get_first_connector(struct vkms_config *config) 62 + { 63 + struct vkms_config_connector *connector_cfg; 64 + 65 + vkms_config_for_each_connector(config, connector_cfg) 66 + return connector_cfg; 67 + 68 + return NULL; 69 + } 70 + 72 71 struct default_config_case { 73 72 bool enable_cursor; 74 73 bool enable_writeback; ··· 100 79 KUNIT_EXPECT_EQ(test, vkms_config_get_num_planes(config), 0); 101 80 KUNIT_EXPECT_EQ(test, vkms_config_get_num_crtcs(config), 0); 102 81 KUNIT_EXPECT_EQ(test, vkms_config_get_num_encoders(config), 0); 82 + KUNIT_EXPECT_EQ(test, vkms_config_get_num_connectors(config), 0); 103 83 104 84 KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config)); 105 85 ··· 176 154 177 155 /* Encoders */ 178 156 KUNIT_EXPECT_EQ(test, vkms_config_get_num_encoders(config), 1); 157 + 158 + /* Connectors */ 159 + KUNIT_EXPECT_EQ(test, vkms_config_get_num_connectors(config), 1); 179 160 180 161 KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config)); 181 162 ··· 305 280 } 306 281 KUNIT_ASSERT_EQ(test, n_encoders, 1); 307 282 n_encoders = 0; 283 + 284 + vkms_config_destroy(config); 285 + } 286 + 287 + static void vkms_config_test_get_connectors(struct kunit *test) 288 + { 289 + struct vkms_config *config; 290 + struct vkms_config_connector *connector_cfg; 291 + struct vkms_config_connector *connector_cfg1, *connector_cfg2; 292 + int n_connectors = 0; 293 + 294 + config = vkms_config_create("test"); 295 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config); 296 + 297 + vkms_config_for_each_connector(config, connector_cfg) 298 + n_connectors++; 299 + KUNIT_ASSERT_EQ(test, n_connectors, 0); 300 + 301 + connector_cfg1 = vkms_config_create_connector(config); 302 + vkms_config_for_each_connector(config, connector_cfg) { 303 + n_connectors++; 304 + if (connector_cfg != connector_cfg1) 305 + KUNIT_FAIL(test, "Unexpected connector"); 306 + } 307 + KUNIT_ASSERT_EQ(test, n_connectors, 1); 308 + n_connectors = 0; 309 + 310 + connector_cfg2 = vkms_config_create_connector(config); 311 + vkms_config_for_each_connector(config, connector_cfg) { 312 + n_connectors++; 313 + if (connector_cfg != connector_cfg1 && 314 + connector_cfg != connector_cfg2) 315 + KUNIT_FAIL(test, "Unexpected connector"); 316 + } 317 + KUNIT_ASSERT_EQ(test, n_connectors, 2); 318 + n_connectors = 0; 319 + 320 + vkms_config_destroy_connector(connector_cfg2); 321 + vkms_config_for_each_connector(config, connector_cfg) { 322 + n_connectors++; 323 + if (connector_cfg != connector_cfg1) 324 + KUNIT_FAIL(test, "Unexpected connector"); 325 + } 326 + KUNIT_ASSERT_EQ(test, n_connectors, 1); 327 + n_connectors = 0; 308 328 309 329 vkms_config_destroy(config); 310 330 } ··· 557 487 vkms_config_destroy_plane(plane_cfg); 558 488 vkms_config_destroy_crtc(config, crtc_cfg2); 559 489 KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config)); 490 + 491 + vkms_config_destroy(config); 492 + } 493 + 494 + static void vkms_config_test_invalid_connector_number(struct kunit *test) 495 + { 496 + struct vkms_config *config; 497 + struct vkms_config_connector *connector_cfg; 498 + int n; 499 + 500 + config = vkms_config_default_create(false, false, false); 501 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config); 502 + 503 + /* Invalid: No connectors */ 504 + connector_cfg = get_first_connector(config); 505 + vkms_config_destroy_connector(connector_cfg); 506 + KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config)); 507 + 508 + /* Invalid: Too many connectors */ 509 + for (n = 0; n <= 32; n++) 510 + connector_cfg = vkms_config_create_connector(config); 511 + 512 + KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config)); 560 513 561 514 vkms_config_destroy(config); 562 515 } ··· 823 730 KUNIT_CASE(vkms_config_test_get_planes), 824 731 KUNIT_CASE(vkms_config_test_get_crtcs), 825 732 KUNIT_CASE(vkms_config_test_get_encoders), 733 + KUNIT_CASE(vkms_config_test_get_connectors), 826 734 KUNIT_CASE(vkms_config_test_invalid_plane_number), 827 735 KUNIT_CASE(vkms_config_test_valid_plane_type), 828 736 KUNIT_CASE(vkms_config_test_valid_plane_possible_crtcs), 829 737 KUNIT_CASE(vkms_config_test_invalid_crtc_number), 830 738 KUNIT_CASE(vkms_config_test_invalid_encoder_number), 831 739 KUNIT_CASE(vkms_config_test_valid_encoder_possible_crtcs), 740 + KUNIT_CASE(vkms_config_test_invalid_connector_number), 832 741 KUNIT_CASE(vkms_config_test_attach_different_configs), 833 742 KUNIT_CASE(vkms_config_test_plane_attach_crtc), 834 743 KUNIT_CASE(vkms_config_test_plane_get_possible_crtcs),
+54
drivers/gpu/drm/vkms/vkms_config.c
··· 25 25 INIT_LIST_HEAD(&config->planes); 26 26 INIT_LIST_HEAD(&config->crtcs); 27 27 INIT_LIST_HEAD(&config->encoders); 28 + INIT_LIST_HEAD(&config->connectors); 28 29 29 30 return config; 30 31 } ··· 39 38 struct vkms_config_plane *plane_cfg; 40 39 struct vkms_config_crtc *crtc_cfg; 41 40 struct vkms_config_encoder *encoder_cfg; 41 + struct vkms_config_connector *connector_cfg; 42 42 int n; 43 43 44 44 config = vkms_config_create(DEFAULT_DEVICE_NAME); ··· 91 89 if (vkms_config_encoder_attach_crtc(encoder_cfg, crtc_cfg)) 92 90 goto err_alloc; 93 91 92 + connector_cfg = vkms_config_create_connector(config); 93 + if (IS_ERR(connector_cfg)) 94 + goto err_alloc; 95 + 94 96 return config; 95 97 96 98 err_alloc: ··· 108 102 struct vkms_config_plane *plane_cfg, *plane_tmp; 109 103 struct vkms_config_crtc *crtc_cfg, *crtc_tmp; 110 104 struct vkms_config_encoder *encoder_cfg, *encoder_tmp; 105 + struct vkms_config_connector *connector_cfg, *connector_tmp; 111 106 112 107 list_for_each_entry_safe(plane_cfg, plane_tmp, &config->planes, link) 113 108 vkms_config_destroy_plane(plane_cfg); ··· 118 111 119 112 list_for_each_entry_safe(encoder_cfg, encoder_tmp, &config->encoders, link) 120 113 vkms_config_destroy_encoder(config, encoder_cfg); 114 + 115 + list_for_each_entry_safe(connector_cfg, connector_tmp, &config->connectors, link) 116 + vkms_config_destroy_connector(connector_cfg); 121 117 122 118 kfree_const(config->dev_name); 123 119 kfree(config); ··· 265 255 return true; 266 256 } 267 257 258 + static bool valid_connector_number(const struct vkms_config *config) 259 + { 260 + struct drm_device *dev = config->dev ? &config->dev->drm : NULL; 261 + size_t n_connectors; 262 + 263 + n_connectors = list_count_nodes((struct list_head *)&config->connectors); 264 + if (n_connectors <= 0 || n_connectors >= 32) { 265 + drm_info(dev, "The number of connectors must be between 1 and 31\n"); 266 + return false; 267 + } 268 + 269 + return true; 270 + } 271 + 268 272 bool vkms_config_is_valid(const struct vkms_config *config) 269 273 { 270 274 struct vkms_config_crtc *crtc_cfg; ··· 290 266 return false; 291 267 292 268 if (!valid_encoder_number(config)) 269 + return false; 270 + 271 + if (!valid_connector_number(config)) 293 272 return false; 294 273 295 274 if (!valid_plane_possible_crtcs(config)) ··· 319 292 struct vkms_config_plane *plane_cfg; 320 293 struct vkms_config_crtc *crtc_cfg; 321 294 struct vkms_config_encoder *encoder_cfg; 295 + struct vkms_config_connector *connector_cfg; 322 296 323 297 dev_name = vkms_config_get_device_name((struct vkms_config *)vkmsdev->config); 324 298 seq_printf(m, "dev_name=%s\n", dev_name); ··· 338 310 339 311 vkms_config_for_each_encoder(vkmsdev->config, encoder_cfg) 340 312 seq_puts(m, "encoder\n"); 313 + 314 + vkms_config_for_each_connector(vkmsdev->config, connector_cfg) 315 + seq_puts(m, "connector\n"); 341 316 342 317 return 0; 343 318 } ··· 551 520 } 552 521 } 553 522 EXPORT_SYMBOL_IF_KUNIT(vkms_config_encoder_detach_crtc); 523 + 524 + struct vkms_config_connector *vkms_config_create_connector(struct vkms_config *config) 525 + { 526 + struct vkms_config_connector *connector_cfg; 527 + 528 + connector_cfg = kzalloc(sizeof(*connector_cfg), GFP_KERNEL); 529 + if (!connector_cfg) 530 + return ERR_PTR(-ENOMEM); 531 + 532 + connector_cfg->config = config; 533 + 534 + list_add_tail(&connector_cfg->link, &config->connectors); 535 + 536 + return connector_cfg; 537 + } 538 + EXPORT_SYMBOL_IF_KUNIT(vkms_config_create_connector); 539 + 540 + void vkms_config_destroy_connector(struct vkms_config_connector *connector_cfg) 541 + { 542 + list_del(&connector_cfg->link); 543 + kfree(connector_cfg); 544 + } 545 + EXPORT_SYMBOL_IF_KUNIT(vkms_config_destroy_connector);
+44
drivers/gpu/drm/vkms/vkms_config.h
··· 16 16 * @planes: List of planes configured for the device 17 17 * @crtcs: List of CRTCs configured for the device 18 18 * @encoders: List of encoders configured for the device 19 + * @connectors: List of connectors configured for the device 19 20 * @dev: Used to store the current VKMS device. Only set when the device is instantiated. 20 21 */ 21 22 struct vkms_config { ··· 24 23 struct list_head planes; 25 24 struct list_head crtcs; 26 25 struct list_head encoders; 26 + struct list_head connectors; 27 27 struct vkms_device *dev; 28 28 }; 29 29 ··· 95 93 }; 96 94 97 95 /** 96 + * struct vkms_config_connector 97 + * 98 + * @link: Link to the others connector in vkms_config 99 + * @config: The vkms_config this connector belongs to 100 + * @connector: Internal usage. This pointer should never be considered as valid. 101 + * It can be used to store a temporary reference to a VKMS connector 102 + * during device creation. This pointer is not managed by the 103 + * configuration and must be managed by other means. 104 + */ 105 + struct vkms_config_connector { 106 + struct list_head link; 107 + struct vkms_config *config; 108 + 109 + /* Internal usage */ 110 + struct vkms_connector *connector; 111 + }; 112 + 113 + /** 98 114 * vkms_config_for_each_plane - Iterate over the vkms_config planes 99 115 * @config: &struct vkms_config pointer 100 116 * @plane_cfg: &struct vkms_config_plane pointer used as cursor ··· 135 115 */ 136 116 #define vkms_config_for_each_encoder(config, encoder_cfg) \ 137 117 list_for_each_entry((encoder_cfg), &(config)->encoders, link) 118 + 119 + /** 120 + * vkms_config_for_each_connector - Iterate over the vkms_config connectors 121 + * @config: &struct vkms_config pointer 122 + * @connector_cfg: &struct vkms_config_connector pointer used as cursor 123 + */ 124 + #define vkms_config_for_each_connector(config, connector_cfg) \ 125 + list_for_each_entry((connector_cfg), &(config)->connectors, link) 138 126 139 127 /** 140 128 * vkms_config_plane_for_each_possible_crtc - Iterate over the vkms_config_plane ··· 388 360 */ 389 361 void vkms_config_encoder_detach_crtc(struct vkms_config_encoder *encoder_cfg, 390 362 struct vkms_config_crtc *crtc_cfg); 363 + 364 + /** 365 + * vkms_config_create_connector() - Add a new connector configuration 366 + * @config: Configuration to add the connector to 367 + * 368 + * Returns: 369 + * The new connector configuration or an error. Call 370 + * vkms_config_destroy_connector() to free the returned connector configuration. 371 + */ 372 + struct vkms_config_connector *vkms_config_create_connector(struct vkms_config *config); 373 + 374 + /** 375 + * vkms_config_destroy_connector() - Remove and free a connector configuration 376 + * @connector_cfg: Connector configuration to destroy 377 + */ 378 + void vkms_config_destroy_connector(struct vkms_config_connector *connector_cfg); 391 379 392 380 #endif /* _VKMS_CONFIG_H_ */
+11
drivers/gpu/drm/vkms/vkms_connector.c
··· 25 25 return count; 26 26 } 27 27 28 + static struct drm_encoder *vkms_conn_best_encoder(struct drm_connector *connector) 29 + { 30 + struct drm_encoder *encoder; 31 + 32 + drm_connector_for_each_possible_encoder(connector, encoder) 33 + return encoder; 34 + 35 + return NULL; 36 + } 37 + 28 38 static const struct drm_connector_helper_funcs vkms_conn_helper_funcs = { 29 39 .get_modes = vkms_conn_get_modes, 40 + .best_encoder = vkms_conn_best_encoder, 30 41 }; 31 42 32 43 struct vkms_connector *vkms_connector_init(struct vkms_device *vkmsdev)