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 encoders and CRTCs

Add a list of possible CRTCs to the encoder configuration and helpers to
attach and detach them.

Now that the default configuration has its encoder and CRTC correctly
attached, 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-13-jose.exposito89@gmail.com
Signed-off-by: Maxime Ripard <mripard@kernel.org>

authored by

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

+266 -20
+1
.clang-format
··· 693 693 - 'vkms_config_for_each_crtc' 694 694 - 'vkms_config_for_each_encoder' 695 695 - 'vkms_config_for_each_plane' 696 + - 'vkms_config_encoder_for_each_possible_crtc' 696 697 - 'vkms_config_plane_for_each_possible_crtc' 697 698 - 'while_for_each_ftrace_op' 698 699 - 'xa_for_each'
+125
drivers/gpu/drm/vkms/tests/vkms_config_test.c
··· 312 312 struct vkms_config *config; 313 313 struct vkms_config_plane *plane_cfg; 314 314 struct vkms_config_crtc *crtc_cfg; 315 + struct vkms_config_encoder *encoder_cfg; 315 316 int err; 316 317 317 318 config = vkms_config_default_create(false, false, false); ··· 366 365 367 366 /* Invalid: Second CRTC without primary plane */ 368 367 crtc_cfg = vkms_config_create_crtc(config); 368 + encoder_cfg = vkms_config_create_encoder(config); 369 + err = vkms_config_encoder_attach_crtc(encoder_cfg, crtc_cfg); 370 + KUNIT_EXPECT_EQ(test, err, 0); 369 371 KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config)); 370 372 371 373 /* Valid: Second CRTC with a primary plane */ ··· 446 442 vkms_config_destroy(config); 447 443 } 448 444 445 + static void vkms_config_test_valid_encoder_possible_crtcs(struct kunit *test) 446 + { 447 + struct vkms_config *config; 448 + struct vkms_config_plane *plane_cfg; 449 + struct vkms_config_crtc *crtc_cfg1, *crtc_cfg2; 450 + struct vkms_config_encoder *encoder_cfg; 451 + int err; 452 + 453 + config = vkms_config_default_create(false, false, false); 454 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config); 455 + 456 + crtc_cfg1 = get_first_crtc(config); 457 + 458 + /* Invalid: Encoder without a possible CRTC */ 459 + encoder_cfg = vkms_config_create_encoder(config); 460 + KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config)); 461 + 462 + /* Valid: Second CRTC with shared encoder */ 463 + crtc_cfg2 = vkms_config_create_crtc(config); 464 + 465 + plane_cfg = vkms_config_create_plane(config); 466 + vkms_config_plane_set_type(plane_cfg, DRM_PLANE_TYPE_PRIMARY); 467 + err = vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg2); 468 + KUNIT_EXPECT_EQ(test, err, 0); 469 + 470 + err = vkms_config_encoder_attach_crtc(encoder_cfg, crtc_cfg1); 471 + KUNIT_EXPECT_EQ(test, err, 0); 472 + 473 + err = vkms_config_encoder_attach_crtc(encoder_cfg, crtc_cfg2); 474 + KUNIT_EXPECT_EQ(test, err, 0); 475 + 476 + KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config)); 477 + 478 + /* Invalid: Second CRTC without encoders */ 479 + vkms_config_encoder_detach_crtc(encoder_cfg, crtc_cfg2); 480 + KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config)); 481 + 482 + /* Valid: First CRTC with 2 possible encoder */ 483 + vkms_config_destroy_plane(plane_cfg); 484 + vkms_config_destroy_crtc(config, crtc_cfg2); 485 + KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config)); 486 + 487 + vkms_config_destroy(config); 488 + } 489 + 449 490 static void vkms_config_test_attach_different_configs(struct kunit *test) 450 491 { 451 492 struct vkms_config *config1, *config2; 452 493 struct vkms_config_plane *plane_cfg1, *plane_cfg2; 453 494 struct vkms_config_crtc *crtc_cfg1, *crtc_cfg2; 495 + struct vkms_config_encoder *encoder_cfg1, *encoder_cfg2; 454 496 int err; 455 497 456 498 config1 = vkms_config_create("test1"); ··· 507 457 508 458 plane_cfg1 = vkms_config_create_plane(config1); 509 459 crtc_cfg1 = vkms_config_create_crtc(config1); 460 + encoder_cfg1 = vkms_config_create_encoder(config1); 510 461 511 462 plane_cfg2 = vkms_config_create_plane(config2); 512 463 crtc_cfg2 = vkms_config_create_crtc(config2); 464 + encoder_cfg2 = vkms_config_create_encoder(config2); 513 465 514 466 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_cfg1); 515 467 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_cfg2); 516 468 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_cfg1); 517 469 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_cfg2); 470 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder_cfg1); 471 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder_cfg2); 518 472 519 473 err = vkms_config_plane_attach_crtc(plane_cfg1, crtc_cfg2); 520 474 KUNIT_EXPECT_NE(test, err, 0); 521 475 err = vkms_config_plane_attach_crtc(plane_cfg2, crtc_cfg1); 476 + KUNIT_EXPECT_NE(test, err, 0); 477 + 478 + err = vkms_config_encoder_attach_crtc(encoder_cfg1, crtc_cfg2); 479 + KUNIT_EXPECT_NE(test, err, 0); 480 + err = vkms_config_encoder_attach_crtc(encoder_cfg2, crtc_cfg1); 522 481 KUNIT_EXPECT_NE(test, err, 0); 523 482 524 483 vkms_config_destroy(config1); ··· 659 600 vkms_config_destroy(config); 660 601 } 661 602 603 + static void vkms_config_test_encoder_get_possible_crtcs(struct kunit *test) 604 + { 605 + struct vkms_config *config; 606 + struct vkms_config_encoder *encoder_cfg1, *encoder_cfg2; 607 + struct vkms_config_crtc *crtc_cfg1, *crtc_cfg2; 608 + struct vkms_config_crtc *possible_crtc; 609 + unsigned long idx = 0; 610 + int n_crtcs = 0; 611 + int err; 612 + 613 + config = vkms_config_create("test"); 614 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config); 615 + 616 + encoder_cfg1 = vkms_config_create_encoder(config); 617 + encoder_cfg2 = vkms_config_create_encoder(config); 618 + crtc_cfg1 = vkms_config_create_crtc(config); 619 + crtc_cfg2 = vkms_config_create_crtc(config); 620 + 621 + /* No possible CRTCs */ 622 + vkms_config_encoder_for_each_possible_crtc(encoder_cfg1, idx, possible_crtc) 623 + KUNIT_FAIL(test, "Unexpected possible CRTC"); 624 + 625 + vkms_config_encoder_for_each_possible_crtc(encoder_cfg2, idx, possible_crtc) 626 + KUNIT_FAIL(test, "Unexpected possible CRTC"); 627 + 628 + /* Encoder 1 attached to CRTC 1 and 2 */ 629 + err = vkms_config_encoder_attach_crtc(encoder_cfg1, crtc_cfg1); 630 + KUNIT_EXPECT_EQ(test, err, 0); 631 + err = vkms_config_encoder_attach_crtc(encoder_cfg1, crtc_cfg2); 632 + KUNIT_EXPECT_EQ(test, err, 0); 633 + 634 + vkms_config_encoder_for_each_possible_crtc(encoder_cfg1, idx, possible_crtc) { 635 + n_crtcs++; 636 + if (possible_crtc != crtc_cfg1 && possible_crtc != crtc_cfg2) 637 + KUNIT_FAIL(test, "Unexpected possible CRTC"); 638 + } 639 + KUNIT_ASSERT_EQ(test, n_crtcs, 2); 640 + n_crtcs = 0; 641 + 642 + vkms_config_encoder_for_each_possible_crtc(encoder_cfg2, idx, possible_crtc) 643 + KUNIT_FAIL(test, "Unexpected possible CRTC"); 644 + 645 + /* Encoder 1 attached to CRTC 1 and encoder 2 to CRTC 2 */ 646 + vkms_config_encoder_detach_crtc(encoder_cfg1, crtc_cfg2); 647 + vkms_config_encoder_for_each_possible_crtc(encoder_cfg1, idx, possible_crtc) { 648 + n_crtcs++; 649 + if (possible_crtc != crtc_cfg1) 650 + KUNIT_FAIL(test, "Unexpected possible CRTC"); 651 + } 652 + KUNIT_ASSERT_EQ(test, n_crtcs, 1); 653 + n_crtcs = 0; 654 + 655 + err = vkms_config_encoder_attach_crtc(encoder_cfg2, crtc_cfg2); 656 + KUNIT_EXPECT_EQ(test, err, 0); 657 + vkms_config_encoder_for_each_possible_crtc(encoder_cfg2, idx, possible_crtc) { 658 + n_crtcs++; 659 + if (possible_crtc != crtc_cfg2) 660 + KUNIT_FAIL(test, "Unexpected possible CRTC"); 661 + } 662 + KUNIT_ASSERT_EQ(test, n_crtcs, 1); 663 + 664 + vkms_config_destroy(config); 665 + } 666 + 662 667 static struct kunit_case vkms_config_test_cases[] = { 663 668 KUNIT_CASE(vkms_config_test_empty_config), 664 669 KUNIT_CASE_PARAM(vkms_config_test_default_config, ··· 735 612 KUNIT_CASE(vkms_config_test_valid_plane_possible_crtcs), 736 613 KUNIT_CASE(vkms_config_test_invalid_crtc_number), 737 614 KUNIT_CASE(vkms_config_test_invalid_encoder_number), 615 + KUNIT_CASE(vkms_config_test_valid_encoder_possible_crtcs), 738 616 KUNIT_CASE(vkms_config_test_attach_different_configs), 739 617 KUNIT_CASE(vkms_config_test_plane_attach_crtc), 740 618 KUNIT_CASE(vkms_config_test_plane_get_possible_crtcs), 619 + KUNIT_CASE(vkms_config_test_encoder_get_possible_crtcs), 741 620 {} 742 621 }; 743 622
+82
drivers/gpu/drm/vkms/vkms_config.c
··· 86 86 if (IS_ERR(encoder_cfg)) 87 87 goto err_alloc; 88 88 89 + if (vkms_config_encoder_attach_crtc(encoder_cfg, crtc_cfg)) 90 + goto err_alloc; 91 + 89 92 return config; 90 93 91 94 err_alloc: ··· 219 216 return true; 220 217 } 221 218 219 + static bool valid_encoder_possible_crtcs(const struct vkms_config *config) 220 + { 221 + struct drm_device *dev = config->dev ? &config->dev->drm : NULL; 222 + struct vkms_config_crtc *crtc_cfg; 223 + struct vkms_config_encoder *encoder_cfg; 224 + 225 + vkms_config_for_each_encoder(config, encoder_cfg) { 226 + if (xa_empty(&encoder_cfg->possible_crtcs)) { 227 + drm_info(dev, "All encoders must have at least one possible CRTC\n"); 228 + return false; 229 + } 230 + } 231 + 232 + vkms_config_for_each_crtc(config, crtc_cfg) { 233 + bool crtc_has_encoder = false; 234 + 235 + vkms_config_for_each_encoder(config, encoder_cfg) { 236 + struct vkms_config_crtc *possible_crtc; 237 + unsigned long idx = 0; 238 + 239 + vkms_config_encoder_for_each_possible_crtc(encoder_cfg, 240 + idx, possible_crtc) { 241 + if (possible_crtc == crtc_cfg) 242 + crtc_has_encoder = true; 243 + } 244 + } 245 + 246 + if (!crtc_has_encoder) { 247 + drm_info(dev, "All CRTCs must have at least one possible encoder\n"); 248 + return false; 249 + } 250 + } 251 + 252 + return true; 253 + } 254 + 222 255 bool vkms_config_is_valid(const struct vkms_config *config) 223 256 { 224 257 struct vkms_config_crtc *crtc_cfg; ··· 275 236 if (!valid_planes_for_crtc(config, crtc_cfg)) 276 237 return false; 277 238 } 239 + 240 + if (!valid_encoder_possible_crtcs(config)) 241 + return false; 278 242 279 243 return true; 280 244 } ··· 404 362 struct vkms_config_crtc *crtc_cfg) 405 363 { 406 364 struct vkms_config_plane *plane_cfg; 365 + struct vkms_config_encoder *encoder_cfg; 407 366 408 367 vkms_config_for_each_plane(config, plane_cfg) 409 368 vkms_config_plane_detach_crtc(plane_cfg, crtc_cfg); 369 + 370 + vkms_config_for_each_encoder(config, encoder_cfg) 371 + vkms_config_encoder_detach_crtc(encoder_cfg, crtc_cfg); 410 372 411 373 list_del(&crtc_cfg->link); 412 374 kfree(crtc_cfg); ··· 471 425 return ERR_PTR(-ENOMEM); 472 426 473 427 encoder_cfg->config = config; 428 + xa_init_flags(&encoder_cfg->possible_crtcs, XA_FLAGS_ALLOC); 429 + 474 430 list_add_tail(&encoder_cfg->link, &config->encoders); 475 431 476 432 return encoder_cfg; ··· 482 434 void vkms_config_destroy_encoder(struct vkms_config *config, 483 435 struct vkms_config_encoder *encoder_cfg) 484 436 { 437 + xa_destroy(&encoder_cfg->possible_crtcs); 485 438 list_del(&encoder_cfg->link); 486 439 kfree(encoder_cfg); 487 440 } 488 441 EXPORT_SYMBOL_IF_KUNIT(vkms_config_destroy_encoder); 442 + 443 + int __must_check vkms_config_encoder_attach_crtc(struct vkms_config_encoder *encoder_cfg, 444 + struct vkms_config_crtc *crtc_cfg) 445 + { 446 + struct vkms_config_crtc *possible_crtc; 447 + unsigned long idx = 0; 448 + u32 crtc_idx = 0; 449 + 450 + if (encoder_cfg->config != crtc_cfg->config) 451 + return -EINVAL; 452 + 453 + vkms_config_encoder_for_each_possible_crtc(encoder_cfg, idx, possible_crtc) { 454 + if (possible_crtc == crtc_cfg) 455 + return -EEXIST; 456 + } 457 + 458 + return xa_alloc(&encoder_cfg->possible_crtcs, &crtc_idx, crtc_cfg, 459 + xa_limit_32b, GFP_KERNEL); 460 + } 461 + EXPORT_SYMBOL_IF_KUNIT(vkms_config_encoder_attach_crtc); 462 + 463 + void vkms_config_encoder_detach_crtc(struct vkms_config_encoder *encoder_cfg, 464 + struct vkms_config_crtc *crtc_cfg) 465 + { 466 + struct vkms_config_crtc *possible_crtc; 467 + unsigned long idx = 0; 468 + 469 + vkms_config_encoder_for_each_possible_crtc(encoder_cfg, idx, possible_crtc) { 470 + if (possible_crtc == crtc_cfg) 471 + xa_erase(&encoder_cfg->possible_crtcs, idx); 472 + } 473 + } 474 + EXPORT_SYMBOL_IF_KUNIT(vkms_config_encoder_detach_crtc);
+29
drivers/gpu/drm/vkms/vkms_config.h
··· 76 76 * 77 77 * @link: Link to the others encoders in vkms_config 78 78 * @config: The vkms_config this CRTC belongs to 79 + * @possible_crtcs: Array of CRTCs that can be used with this encoder 79 80 * @encoder: Internal usage. This pointer should never be considered as valid. 80 81 * It can be used to store a temporary reference to a VKMS encoder 81 82 * during device creation. This pointer is not managed by the ··· 85 84 struct vkms_config_encoder { 86 85 struct list_head link; 87 86 struct vkms_config *config; 87 + 88 + struct xarray possible_crtcs; 88 89 89 90 /* Internal usage */ 90 91 struct drm_encoder *encoder; ··· 125 122 */ 126 123 #define vkms_config_plane_for_each_possible_crtc(plane_cfg, idx, possible_crtc) \ 127 124 xa_for_each(&(plane_cfg)->possible_crtcs, idx, (possible_crtc)) 125 + 126 + /** 127 + * vkms_config_encoder_for_each_possible_crtc - Iterate over the 128 + * vkms_config_encoder possible CRTCs 129 + * @encoder_cfg: &struct vkms_config_encoder pointer 130 + * @idx: Index of the cursor 131 + * @possible_crtc: &struct vkms_config_crtc pointer used as cursor 132 + */ 133 + #define vkms_config_encoder_for_each_possible_crtc(encoder_cfg, idx, possible_crtc) \ 134 + xa_for_each(&(encoder_cfg)->possible_crtcs, idx, (possible_crtc)) 128 135 129 136 /** 130 137 * vkms_config_create() - Create a new VKMS configuration ··· 344 331 */ 345 332 void vkms_config_destroy_encoder(struct vkms_config *config, 346 333 struct vkms_config_encoder *encoder_cfg); 334 + 335 + /** 336 + * vkms_config_encoder_attach_crtc - Attach a encoder to a CRTC 337 + * @encoder_cfg: Encoder to attach 338 + * @crtc_cfg: CRTC to attach @encoder_cfg to 339 + */ 340 + int __must_check vkms_config_encoder_attach_crtc(struct vkms_config_encoder *encoder_cfg, 341 + struct vkms_config_crtc *crtc_cfg); 342 + 343 + /** 344 + * vkms_config_encoder_detach_crtc - Detach a encoder from a CRTC 345 + * @encoder_cfg: Encoder to detach 346 + * @crtc_cfg: CRTC to detach @encoder_cfg from 347 + */ 348 + void vkms_config_encoder_detach_crtc(struct vkms_config_encoder *encoder_cfg, 349 + struct vkms_config_crtc *crtc_cfg); 347 350 348 351 #endif /* _VKMS_CONFIG_H_ */
+29 -20
drivers/gpu/drm/vkms/vkms_output.c
··· 9 9 { 10 10 struct drm_device *dev = &vkmsdev->drm; 11 11 struct vkms_connector *connector; 12 - struct drm_encoder *encoder; 13 12 struct vkms_config_plane *plane_cfg; 14 13 struct vkms_config_crtc *crtc_cfg; 14 + struct vkms_config_encoder *encoder_cfg; 15 15 int ret; 16 16 int writeback; 17 17 ··· 61 61 } 62 62 } 63 63 64 + vkms_config_for_each_encoder(vkmsdev->config, encoder_cfg) { 65 + struct vkms_config_crtc *possible_crtc; 66 + unsigned long idx = 0; 67 + 68 + encoder_cfg->encoder = drmm_kzalloc(dev, sizeof(*encoder_cfg->encoder), GFP_KERNEL); 69 + if (!encoder_cfg->encoder) { 70 + DRM_ERROR("Failed to allocate encoder\n"); 71 + return -ENOMEM; 72 + } 73 + ret = drmm_encoder_init(dev, encoder_cfg->encoder, NULL, 74 + DRM_MODE_ENCODER_VIRTUAL, NULL); 75 + if (ret) { 76 + DRM_ERROR("Failed to init encoder\n"); 77 + return ret; 78 + } 79 + 80 + vkms_config_encoder_for_each_possible_crtc(encoder_cfg, idx, possible_crtc) { 81 + encoder_cfg->encoder->possible_crtcs |= 82 + drm_crtc_mask(&possible_crtc->crtc->crtc); 83 + } 84 + } 85 + 64 86 connector = vkms_connector_init(vkmsdev); 65 87 if (IS_ERR(connector)) { 66 88 DRM_ERROR("Failed to init connector\n"); 67 89 return PTR_ERR(connector); 68 90 } 69 91 70 - encoder = drmm_kzalloc(dev, sizeof(*encoder), GFP_KERNEL); 71 - if (!encoder) { 72 - DRM_ERROR("Failed to allocate encoder\n"); 73 - return -ENOMEM; 74 - } 75 - ret = drmm_encoder_init(dev, encoder, NULL, 76 - DRM_MODE_ENCODER_VIRTUAL, NULL); 77 - if (ret) { 78 - DRM_ERROR("Failed to init encoder\n"); 79 - return ret; 80 - } 81 - 82 - vkms_config_for_each_crtc(vkmsdev->config, crtc_cfg) 83 - encoder->possible_crtcs = drm_crtc_mask(&crtc_cfg->crtc->crtc); 84 - 85 92 /* Attach the encoder and the connector */ 86 - ret = drm_connector_attach_encoder(&connector->base, encoder); 87 - if (ret) { 88 - DRM_ERROR("Failed to attach connector to encoder\n"); 89 - return ret; 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; 98 + } 90 99 } 91 100 92 101 drm_mode_config_reset(dev);