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 attach connectors and encoders

Add a list of possible encoders to the connector configuration and
helpers to attach and detach them.

Now that the default configuration has its connector and encoder
correctly, configure the output following the configuration.

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-15-jose.exposito89@gmail.com
Signed-off-by: Maxime Ripard <mripard@kernel.org>

authored by

José Expósito and committed by
Maxime Ripard
2c7aafc0 da38c720

+216 -13
+1
.clang-format
··· 694 694 - 'vkms_config_for_each_crtc' 695 695 - 'vkms_config_for_each_encoder' 696 696 - 'vkms_config_for_each_plane' 697 + - 'vkms_config_connector_for_each_possible_encoder' 697 698 - 'vkms_config_encoder_for_each_possible_crtc' 698 699 - 'vkms_config_plane_for_each_possible_crtc' 699 700 - 'while_for_each_ftrace_op'
+102
drivers/gpu/drm/vkms/tests/vkms_config_test.c
··· 584 584 vkms_config_destroy(config); 585 585 } 586 586 587 + static void vkms_config_test_valid_connector_possible_encoders(struct kunit *test) 588 + { 589 + struct vkms_config *config; 590 + struct vkms_config_encoder *encoder_cfg; 591 + struct vkms_config_connector *connector_cfg; 592 + 593 + config = vkms_config_default_create(false, false, false); 594 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config); 595 + 596 + encoder_cfg = get_first_encoder(config); 597 + connector_cfg = get_first_connector(config); 598 + 599 + /* Invalid: Connector without a possible encoder */ 600 + vkms_config_connector_detach_encoder(connector_cfg, encoder_cfg); 601 + KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config)); 602 + 603 + vkms_config_destroy(config); 604 + } 605 + 587 606 static void vkms_config_test_attach_different_configs(struct kunit *test) 588 607 { 589 608 struct vkms_config *config1, *config2; 590 609 struct vkms_config_plane *plane_cfg1, *plane_cfg2; 591 610 struct vkms_config_crtc *crtc_cfg1, *crtc_cfg2; 592 611 struct vkms_config_encoder *encoder_cfg1, *encoder_cfg2; 612 + struct vkms_config_connector *connector_cfg1, *connector_cfg2; 593 613 int err; 594 614 595 615 config1 = vkms_config_create("test1"); ··· 621 601 plane_cfg1 = vkms_config_create_plane(config1); 622 602 crtc_cfg1 = vkms_config_create_crtc(config1); 623 603 encoder_cfg1 = vkms_config_create_encoder(config1); 604 + connector_cfg1 = vkms_config_create_connector(config1); 624 605 625 606 plane_cfg2 = vkms_config_create_plane(config2); 626 607 crtc_cfg2 = vkms_config_create_crtc(config2); 627 608 encoder_cfg2 = vkms_config_create_encoder(config2); 609 + connector_cfg2 = vkms_config_create_connector(config2); 628 610 629 611 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_cfg1); 630 612 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_cfg2); ··· 634 612 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_cfg2); 635 613 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder_cfg1); 636 614 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder_cfg2); 615 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector_cfg1); 616 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector_cfg2); 637 617 638 618 err = vkms_config_plane_attach_crtc(plane_cfg1, crtc_cfg2); 639 619 KUNIT_EXPECT_NE(test, err, 0); ··· 645 621 err = vkms_config_encoder_attach_crtc(encoder_cfg1, crtc_cfg2); 646 622 KUNIT_EXPECT_NE(test, err, 0); 647 623 err = vkms_config_encoder_attach_crtc(encoder_cfg2, crtc_cfg1); 624 + KUNIT_EXPECT_NE(test, err, 0); 625 + 626 + err = vkms_config_connector_attach_encoder(connector_cfg1, encoder_cfg2); 627 + KUNIT_EXPECT_NE(test, err, 0); 628 + err = vkms_config_connector_attach_encoder(connector_cfg2, encoder_cfg1); 648 629 KUNIT_EXPECT_NE(test, err, 0); 649 630 650 631 vkms_config_destroy(config1); ··· 845 816 vkms_config_destroy(config); 846 817 } 847 818 819 + static void vkms_config_test_connector_get_possible_encoders(struct kunit *test) 820 + { 821 + struct vkms_config *config; 822 + struct vkms_config_connector *connector_cfg1, *connector_cfg2; 823 + struct vkms_config_encoder *encoder_cfg1, *encoder_cfg2; 824 + struct vkms_config_encoder *possible_encoder; 825 + unsigned long idx = 0; 826 + int n_encoders = 0; 827 + int err; 828 + 829 + config = vkms_config_create("test"); 830 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config); 831 + 832 + connector_cfg1 = vkms_config_create_connector(config); 833 + connector_cfg2 = vkms_config_create_connector(config); 834 + encoder_cfg1 = vkms_config_create_encoder(config); 835 + encoder_cfg2 = vkms_config_create_encoder(config); 836 + 837 + /* No possible encoders */ 838 + vkms_config_connector_for_each_possible_encoder(connector_cfg1, idx, 839 + possible_encoder) 840 + KUNIT_FAIL(test, "Unexpected possible encoder"); 841 + 842 + vkms_config_connector_for_each_possible_encoder(connector_cfg2, idx, 843 + possible_encoder) 844 + KUNIT_FAIL(test, "Unexpected possible encoder"); 845 + 846 + /* Connector 1 attached to encoders 1 and 2 */ 847 + err = vkms_config_connector_attach_encoder(connector_cfg1, encoder_cfg1); 848 + KUNIT_EXPECT_EQ(test, err, 0); 849 + err = vkms_config_connector_attach_encoder(connector_cfg1, encoder_cfg2); 850 + KUNIT_EXPECT_EQ(test, err, 0); 851 + 852 + vkms_config_connector_for_each_possible_encoder(connector_cfg1, idx, 853 + possible_encoder) { 854 + n_encoders++; 855 + if (possible_encoder != encoder_cfg1 && 856 + possible_encoder != encoder_cfg2) 857 + KUNIT_FAIL(test, "Unexpected possible encoder"); 858 + } 859 + KUNIT_ASSERT_EQ(test, n_encoders, 2); 860 + n_encoders = 0; 861 + 862 + vkms_config_connector_for_each_possible_encoder(connector_cfg2, idx, 863 + possible_encoder) 864 + KUNIT_FAIL(test, "Unexpected possible encoder"); 865 + 866 + /* Connector 1 attached to encoder 1 and connector 2 to encoder 2 */ 867 + vkms_config_connector_detach_encoder(connector_cfg1, encoder_cfg2); 868 + vkms_config_connector_for_each_possible_encoder(connector_cfg1, idx, 869 + possible_encoder) { 870 + n_encoders++; 871 + if (possible_encoder != encoder_cfg1) 872 + KUNIT_FAIL(test, "Unexpected possible encoder"); 873 + } 874 + KUNIT_ASSERT_EQ(test, n_encoders, 1); 875 + n_encoders = 0; 876 + 877 + err = vkms_config_connector_attach_encoder(connector_cfg2, encoder_cfg2); 878 + KUNIT_EXPECT_EQ(test, err, 0); 879 + vkms_config_connector_for_each_possible_encoder(connector_cfg2, idx, 880 + possible_encoder) { 881 + n_encoders++; 882 + if (possible_encoder != encoder_cfg2) 883 + KUNIT_FAIL(test, "Unexpected possible encoder"); 884 + } 885 + KUNIT_ASSERT_EQ(test, n_encoders, 1); 886 + 887 + vkms_config_destroy(config); 888 + } 889 + 848 890 static struct kunit_case vkms_config_test_cases[] = { 849 891 KUNIT_CASE(vkms_config_test_empty_config), 850 892 KUNIT_CASE_PARAM(vkms_config_test_default_config, ··· 931 831 KUNIT_CASE(vkms_config_test_invalid_encoder_number), 932 832 KUNIT_CASE(vkms_config_test_valid_encoder_possible_crtcs), 933 833 KUNIT_CASE(vkms_config_test_invalid_connector_number), 834 + KUNIT_CASE(vkms_config_test_valid_connector_possible_encoders), 934 835 KUNIT_CASE(vkms_config_test_attach_different_configs), 935 836 KUNIT_CASE(vkms_config_test_plane_attach_crtc), 936 837 KUNIT_CASE(vkms_config_test_plane_get_possible_crtcs), 937 838 KUNIT_CASE(vkms_config_test_encoder_get_possible_crtcs), 839 + KUNIT_CASE(vkms_config_test_connector_get_possible_encoders), 938 840 {} 939 841 }; 940 842
+64
drivers/gpu/drm/vkms/vkms_config.c
··· 95 95 if (IS_ERR(connector_cfg)) 96 96 goto err_alloc; 97 97 98 + if (vkms_config_connector_attach_encoder(connector_cfg, encoder_cfg)) 99 + goto err_alloc; 100 + 98 101 return config; 99 102 100 103 err_alloc: ··· 282 279 return true; 283 280 } 284 281 282 + static bool valid_connector_possible_encoders(const struct vkms_config *config) 283 + { 284 + struct drm_device *dev = config->dev ? &config->dev->drm : NULL; 285 + struct vkms_config_connector *connector_cfg; 286 + 287 + vkms_config_for_each_connector(config, connector_cfg) { 288 + if (xa_empty(&connector_cfg->possible_encoders)) { 289 + drm_info(dev, 290 + "All connectors must have at least one possible encoder\n"); 291 + return false; 292 + } 293 + } 294 + 295 + return true; 296 + } 297 + 285 298 bool vkms_config_is_valid(const struct vkms_config *config) 286 299 { 287 300 struct vkms_config_crtc *crtc_cfg; ··· 323 304 } 324 305 325 306 if (!valid_encoder_possible_crtcs(config)) 307 + return false; 308 + 309 + if (!valid_connector_possible_encoders(config)) 326 310 return false; 327 311 328 312 return true; ··· 535 513 void vkms_config_destroy_encoder(struct vkms_config *config, 536 514 struct vkms_config_encoder *encoder_cfg) 537 515 { 516 + struct vkms_config_connector *connector_cfg; 517 + 518 + vkms_config_for_each_connector(config, connector_cfg) 519 + vkms_config_connector_detach_encoder(connector_cfg, encoder_cfg); 520 + 538 521 xa_destroy(&encoder_cfg->possible_crtcs); 539 522 list_del(&encoder_cfg->link); 540 523 kfree(encoder_cfg); ··· 588 561 return ERR_PTR(-ENOMEM); 589 562 590 563 connector_cfg->config = config; 564 + xa_init_flags(&connector_cfg->possible_encoders, XA_FLAGS_ALLOC); 591 565 592 566 list_add_tail(&connector_cfg->link, &config->connectors); 593 567 ··· 598 570 599 571 void vkms_config_destroy_connector(struct vkms_config_connector *connector_cfg) 600 572 { 573 + xa_destroy(&connector_cfg->possible_encoders); 601 574 list_del(&connector_cfg->link); 602 575 kfree(connector_cfg); 603 576 } 604 577 EXPORT_SYMBOL_IF_KUNIT(vkms_config_destroy_connector); 578 + 579 + int __must_check vkms_config_connector_attach_encoder(struct vkms_config_connector *connector_cfg, 580 + struct vkms_config_encoder *encoder_cfg) 581 + { 582 + struct vkms_config_encoder *possible_encoder; 583 + unsigned long idx = 0; 584 + u32 encoder_idx = 0; 585 + 586 + if (connector_cfg->config != encoder_cfg->config) 587 + return -EINVAL; 588 + 589 + vkms_config_connector_for_each_possible_encoder(connector_cfg, idx, 590 + possible_encoder) { 591 + if (possible_encoder == encoder_cfg) 592 + return -EEXIST; 593 + } 594 + 595 + return xa_alloc(&connector_cfg->possible_encoders, &encoder_idx, 596 + encoder_cfg, xa_limit_32b, GFP_KERNEL); 597 + } 598 + EXPORT_SYMBOL_IF_KUNIT(vkms_config_connector_attach_encoder); 599 + 600 + void vkms_config_connector_detach_encoder(struct vkms_config_connector *connector_cfg, 601 + struct vkms_config_encoder *encoder_cfg) 602 + { 603 + struct vkms_config_encoder *possible_encoder; 604 + unsigned long idx = 0; 605 + 606 + vkms_config_connector_for_each_possible_encoder(connector_cfg, idx, 607 + possible_encoder) { 608 + if (possible_encoder == encoder_cfg) 609 + xa_erase(&connector_cfg->possible_encoders, idx); 610 + } 611 + } 612 + EXPORT_SYMBOL_IF_KUNIT(vkms_config_connector_detach_encoder);
+29
drivers/gpu/drm/vkms/vkms_config.h
··· 99 99 * 100 100 * @link: Link to the others connector in vkms_config 101 101 * @config: The vkms_config this connector belongs to 102 + * @possible_encoders: Array of encoders that can be used with this connector 102 103 * @connector: Internal usage. This pointer should never be considered as valid. 103 104 * It can be used to store a temporary reference to a VKMS connector 104 105 * during device creation. This pointer is not managed by the ··· 108 107 struct vkms_config_connector { 109 108 struct list_head link; 110 109 struct vkms_config *config; 110 + 111 + struct xarray possible_encoders; 111 112 112 113 /* Internal usage */ 113 114 struct vkms_connector *connector; ··· 166 163 */ 167 164 #define vkms_config_encoder_for_each_possible_crtc(encoder_cfg, idx, possible_crtc) \ 168 165 xa_for_each(&(encoder_cfg)->possible_crtcs, idx, (possible_crtc)) 166 + 167 + /** 168 + * vkms_config_connector_for_each_possible_encoder - Iterate over the 169 + * vkms_config_connector possible encoders 170 + * @connector_cfg: &struct vkms_config_connector pointer 171 + * @idx: Index of the cursor 172 + * @possible_encoder: &struct vkms_config_encoder pointer used as cursor 173 + */ 174 + #define vkms_config_connector_for_each_possible_encoder(connector_cfg, idx, possible_encoder) \ 175 + xa_for_each(&(connector_cfg)->possible_encoders, idx, (possible_encoder)) 169 176 170 177 /** 171 178 * vkms_config_create() - Create a new VKMS configuration ··· 417 404 * @connector_cfg: Connector configuration to destroy 418 405 */ 419 406 void vkms_config_destroy_connector(struct vkms_config_connector *connector_cfg); 407 + 408 + /** 409 + * vkms_config_connector_attach_encoder - Attach a connector to an encoder 410 + * @connector_cfg: Connector to attach 411 + * @encoder_cfg: Encoder to attach @connector_cfg to 412 + */ 413 + int __must_check vkms_config_connector_attach_encoder(struct vkms_config_connector *connector_cfg, 414 + struct vkms_config_encoder *encoder_cfg); 415 + 416 + /** 417 + * vkms_config_connector_detach_encoder - Detach a connector from an encoder 418 + * @connector_cfg: Connector to detach 419 + * @encoder_cfg: Encoder to detach @connector_cfg from 420 + */ 421 + void vkms_config_connector_detach_encoder(struct vkms_config_connector *connector_cfg, 422 + struct vkms_config_encoder *encoder_cfg); 420 423 421 424 #endif /* _VKMS_CONFIG_H_ */
+20 -13
drivers/gpu/drm/vkms/vkms_output.c
··· 8 8 int vkms_output_init(struct vkms_device *vkmsdev) 9 9 { 10 10 struct drm_device *dev = &vkmsdev->drm; 11 - struct vkms_connector *connector; 12 11 struct vkms_config_plane *plane_cfg; 13 12 struct vkms_config_crtc *crtc_cfg; 14 13 struct vkms_config_encoder *encoder_cfg; 14 + struct vkms_config_connector *connector_cfg; 15 15 int ret; 16 16 int writeback; 17 17 ··· 83 83 } 84 84 } 85 85 86 - connector = vkms_connector_init(vkmsdev); 87 - if (IS_ERR(connector)) { 88 - DRM_ERROR("Failed to init connector\n"); 89 - return PTR_ERR(connector); 90 - } 86 + vkms_config_for_each_connector(vkmsdev->config, connector_cfg) { 87 + struct vkms_config_encoder *possible_encoder; 88 + unsigned long idx = 0; 91 89 92 - /* Attach the encoder and the connector */ 93 - vkms_config_for_each_encoder(vkmsdev->config, encoder_cfg) { 94 - ret = drm_connector_attach_encoder(&connector->base, encoder_cfg->encoder); 95 - if (ret) { 96 - DRM_ERROR("Failed to attach connector to encoder\n"); 97 - return ret; 90 + connector_cfg->connector = vkms_connector_init(vkmsdev); 91 + if (IS_ERR(connector_cfg->connector)) { 92 + DRM_ERROR("Failed to init connector\n"); 93 + return PTR_ERR(connector_cfg->connector); 94 + } 95 + 96 + vkms_config_connector_for_each_possible_encoder(connector_cfg, 97 + idx, 98 + possible_encoder) { 99 + ret = drm_connector_attach_encoder(&connector_cfg->connector->base, 100 + possible_encoder->encoder); 101 + if (ret) { 102 + DRM_ERROR("Failed to attach connector to encoder\n"); 103 + return ret; 104 + } 98 105 } 99 106 } 100 107 101 108 drm_mode_config_reset(dev); 102 109 103 - return ret; 110 + return 0; 104 111 }