FILE
vkms_config.c
File preview with syntax highlighting.
linux-6.19.14/drivers/gpu/drm/vkms/vkms_config.c
1// SPDX-License-Identifier: GPL-2.0+ 2 3#include <linux/slab.h> 4 5#include <drm/drm_print.h> 6#include <drm/drm_debugfs.h> 7#include <kunit/visibility.h> 8 9#include "vkms_config.h" 10 11struct vkms_config *vkms_config_create(const char *dev_name) 12{ 13 struct vkms_config *config; 14 15 config = kzalloc(sizeof(*config), GFP_KERNEL); 16 if (!config) 17 return ERR_PTR(-ENOMEM); 18 19 config->dev_name = kstrdup_const(dev_name, GFP_KERNEL); 20 if (!config->dev_name) { 21 kfree(config); 22 return ERR_PTR(-ENOMEM); 23 } 24 25 INIT_LIST_HEAD(&config->planes); 26 INIT_LIST_HEAD(&config->crtcs); 27 INIT_LIST_HEAD(&config->encoders); 28 INIT_LIST_HEAD(&config->connectors); 29 30 return config; 31} 32EXPORT_SYMBOL_IF_KUNIT(vkms_config_create); 33 34struct vkms_config *vkms_config_default_create(bool enable_cursor, 35 bool enable_writeback, 36 bool enable_overlay, 37 bool enable_plane_pipeline) 38{ 39 struct vkms_config *config; 40 struct vkms_config_plane *plane_cfg; 41 struct vkms_config_crtc *crtc_cfg; 42 struct vkms_config_encoder *encoder_cfg; 43 struct vkms_config_connector *connector_cfg; 44 int n; 45 46 config = vkms_config_create(DEFAULT_DEVICE_NAME); 47 if (IS_ERR(config)) 48 return config; 49 50 plane_cfg = vkms_config_create_plane(config); 51 if (IS_ERR(plane_cfg)) 52 goto err_alloc; 53 vkms_config_plane_set_type(plane_cfg, DRM_PLANE_TYPE_PRIMARY); 54 55 crtc_cfg = vkms_config_create_crtc(config); 56 if (IS_ERR(crtc_cfg)) 57 goto err_alloc; 58 vkms_config_crtc_set_writeback(crtc_cfg, enable_writeback); 59 60 if (vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg)) 61 goto err_alloc; 62 vkms_config_plane_set_default_pipeline(plane_cfg, enable_plane_pipeline); 63 64 if (enable_overlay) { 65 for (n = 0; n < NUM_OVERLAY_PLANES; n++) { 66 plane_cfg = vkms_config_create_plane(config); 67 if (IS_ERR(plane_cfg)) 68 goto err_alloc; 69 70 vkms_config_plane_set_type(plane_cfg, 71 DRM_PLANE_TYPE_OVERLAY); 72 vkms_config_plane_set_default_pipeline(plane_cfg, enable_plane_pipeline); 73 74 if (vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg)) 75 goto err_alloc; 76 } 77 } 78 79 if (enable_cursor) { 80 plane_cfg = vkms_config_create_plane(config); 81 if (IS_ERR(plane_cfg)) 82 goto err_alloc; 83 84 vkms_config_plane_set_type(plane_cfg, DRM_PLANE_TYPE_CURSOR); 85 vkms_config_plane_set_default_pipeline(plane_cfg, enable_plane_pipeline); 86 87 if (vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg)) 88 goto err_alloc; 89 } 90 91 encoder_cfg = vkms_config_create_encoder(config); 92 if (IS_ERR(encoder_cfg)) 93 goto err_alloc; 94 95 if (vkms_config_encoder_attach_crtc(encoder_cfg, crtc_cfg)) 96 goto err_alloc; 97 98 connector_cfg = vkms_config_create_connector(config); 99 if (IS_ERR(connector_cfg)) 100 goto err_alloc; 101 102 if (vkms_config_connector_attach_encoder(connector_cfg, encoder_cfg)) 103 goto err_alloc; 104 105 return config; 106 107err_alloc: 108 vkms_config_destroy(config); 109 return ERR_PTR(-ENOMEM); 110} 111EXPORT_SYMBOL_IF_KUNIT(vkms_config_default_create); 112 113void vkms_config_destroy(struct vkms_config *config) 114{ 115 struct vkms_config_plane *plane_cfg, *plane_tmp; 116 struct vkms_config_crtc *crtc_cfg, *crtc_tmp; 117 struct vkms_config_encoder *encoder_cfg, *encoder_tmp; 118 struct vkms_config_connector *connector_cfg, *connector_tmp; 119 120 list_for_each_entry_safe(plane_cfg, plane_tmp, &config->planes, link) 121 vkms_config_destroy_plane(plane_cfg); 122 123 list_for_each_entry_safe(crtc_cfg, crtc_tmp, &config->crtcs, link) 124 vkms_config_destroy_crtc(config, crtc_cfg); 125 126 list_for_each_entry_safe(encoder_cfg, encoder_tmp, &config->encoders, link) 127 vkms_config_destroy_encoder(config, encoder_cfg); 128 129 list_for_each_entry_safe(connector_cfg, connector_tmp, &config->connectors, link) 130 vkms_config_destroy_connector(connector_cfg); 131 132 kfree_const(config->dev_name); 133 kfree(config); 134} 135EXPORT_SYMBOL_IF_KUNIT(vkms_config_destroy); 136 137static bool valid_plane_number(const struct vkms_config *config) 138{ 139 struct drm_device *dev = config->dev ? &config->dev->drm : NULL; 140 size_t n_planes; 141 142 n_planes = list_count_nodes((struct list_head *)&config->planes); 143 if (n_planes <= 0 || n_planes >= 32) { 144 drm_info(dev, "The number of planes must be between 1 and 31\n"); 145 return false; 146 } 147 148 return true; 149} 150 151static bool valid_planes_for_crtc(const struct vkms_config *config, 152 struct vkms_config_crtc *crtc_cfg) 153{ 154 struct drm_device *dev = config->dev ? &config->dev->drm : NULL; 155 struct vkms_config_plane *plane_cfg; 156 bool has_primary_plane = false; 157 bool has_cursor_plane = false; 158 159 vkms_config_for_each_plane(config, plane_cfg) { 160 struct vkms_config_crtc *possible_crtc; 161 unsigned long idx = 0; 162 enum drm_plane_type type; 163 164 type = vkms_config_plane_get_type(plane_cfg); 165 166 vkms_config_plane_for_each_possible_crtc(plane_cfg, idx, possible_crtc) { 167 if (possible_crtc != crtc_cfg) 168 continue; 169 170 if (type == DRM_PLANE_TYPE_PRIMARY) { 171 if (has_primary_plane) { 172 drm_info(dev, "Multiple primary planes\n"); 173 return false; 174 } 175 176 has_primary_plane = true; 177 } else if (type == DRM_PLANE_TYPE_CURSOR) { 178 if (has_cursor_plane) { 179 drm_info(dev, "Multiple cursor planes\n"); 180 return false; 181 } 182 183 has_cursor_plane = true; 184 } 185 } 186 } 187 188 if (!has_primary_plane) { 189 drm_info(dev, "Primary plane not found\n"); 190 return false; 191 } 192 193 return true; 194} 195 196static bool valid_plane_possible_crtcs(const struct vkms_config *config) 197{ 198 struct drm_device *dev = config->dev ? &config->dev->drm : NULL; 199 struct vkms_config_plane *plane_cfg; 200 201 vkms_config_for_each_plane(config, plane_cfg) { 202 if (xa_empty(&plane_cfg->possible_crtcs)) { 203 drm_info(dev, "All planes must have at least one possible CRTC\n"); 204 return false; 205 } 206 } 207 208 return true; 209} 210 211static bool valid_crtc_number(const struct vkms_config *config) 212{ 213 struct drm_device *dev = config->dev ? &config->dev->drm : NULL; 214 size_t n_crtcs; 215 216 n_crtcs = list_count_nodes((struct list_head *)&config->crtcs); 217 if (n_crtcs <= 0 || n_crtcs >= 32) { 218 drm_info(dev, "The number of CRTCs must be between 1 and 31\n"); 219 return false; 220 } 221 222 return true; 223} 224 225static bool valid_encoder_number(const struct vkms_config *config) 226{ 227 struct drm_device *dev = config->dev ? &config->dev->drm : NULL; 228 size_t n_encoders; 229 230 n_encoders = list_count_nodes((struct list_head *)&config->encoders); 231 if (n_encoders <= 0 || n_encoders >= 32) { 232 drm_info(dev, "The number of encoders must be between 1 and 31\n"); 233 return false; 234 } 235 236 return true; 237} 238 239static bool valid_encoder_possible_crtcs(const struct vkms_config *config) 240{ 241 struct drm_device *dev = config->dev ? &config->dev->drm : NULL; 242 struct vkms_config_crtc *crtc_cfg; 243 struct vkms_config_encoder *encoder_cfg; 244 245 vkms_config_for_each_encoder(config, encoder_cfg) { 246 if (xa_empty(&encoder_cfg->possible_crtcs)) { 247 drm_info(dev, "All encoders must have at least one possible CRTC\n"); 248 return false; 249 } 250 } 251 252 vkms_config_for_each_crtc(config, crtc_cfg) { 253 bool crtc_has_encoder = false; 254 255 vkms_config_for_each_encoder(config, encoder_cfg) { 256 struct vkms_config_crtc *possible_crtc; 257 unsigned long idx = 0; 258 259 vkms_config_encoder_for_each_possible_crtc(encoder_cfg, 260 idx, possible_crtc) { 261 if (possible_crtc == crtc_cfg) 262 crtc_has_encoder = true; 263 } 264 } 265 266 if (!crtc_has_encoder) { 267 drm_info(dev, "All CRTCs must have at least one possible encoder\n"); 268 return false; 269 } 270 } 271 272 return true; 273} 274 275static bool valid_connector_number(const struct vkms_config *config) 276{ 277 struct drm_device *dev = config->dev ? &config->dev->drm : NULL; 278 size_t n_connectors; 279 280 n_connectors = list_count_nodes((struct list_head *)&config->connectors); 281 if (n_connectors <= 0 || n_connectors >= 32) { 282 drm_info(dev, "The number of connectors must be between 1 and 31\n"); 283 return false; 284 } 285 286 return true; 287} 288 289static bool valid_connector_possible_encoders(const struct vkms_config *config) 290{ 291 struct drm_device *dev = config->dev ? &config->dev->drm : NULL; 292 struct vkms_config_connector *connector_cfg; 293 294 vkms_config_for_each_connector(config, connector_cfg) { 295 if (xa_empty(&connector_cfg->possible_encoders)) { 296 drm_info(dev, 297 "All connectors must have at least one possible encoder\n"); 298 return false; 299 } 300 } 301 302 return true; 303} 304 305bool vkms_config_is_valid(const struct vkms_config *config) 306{ 307 struct vkms_config_crtc *crtc_cfg; 308 309 if (!valid_plane_number(config)) 310 return false; 311 312 if (!valid_crtc_number(config)) 313 return false; 314 315 if (!valid_encoder_number(config)) 316 return false; 317 318 if (!valid_connector_number(config)) 319 return false; 320 321 if (!valid_plane_possible_crtcs(config)) 322 return false; 323 324 vkms_config_for_each_crtc(config, crtc_cfg) { 325 if (!valid_planes_for_crtc(config, crtc_cfg)) 326 return false; 327 } 328 329 if (!valid_encoder_possible_crtcs(config)) 330 return false; 331 332 if (!valid_connector_possible_encoders(config)) 333 return false; 334 335 return true; 336} 337EXPORT_SYMBOL_IF_KUNIT(vkms_config_is_valid); 338 339static int vkms_config_show(struct seq_file *m, void *data) 340{ 341 struct drm_debugfs_entry *entry = m->private; 342 struct drm_device *dev = entry->dev; 343 struct vkms_device *vkmsdev = drm_device_to_vkms_device(dev); 344 const char *dev_name; 345 struct vkms_config_plane *plane_cfg; 346 struct vkms_config_crtc *crtc_cfg; 347 struct vkms_config_encoder *encoder_cfg; 348 struct vkms_config_connector *connector_cfg; 349 350 dev_name = vkms_config_get_device_name((struct vkms_config *)vkmsdev->config); 351 seq_printf(m, "dev_name=%s\n", dev_name); 352 353 vkms_config_for_each_plane(vkmsdev->config, plane_cfg) { 354 seq_puts(m, "plane:\n"); 355 seq_printf(m, "\ttype=%d\n", 356 vkms_config_plane_get_type(plane_cfg)); 357 } 358 359 vkms_config_for_each_crtc(vkmsdev->config, crtc_cfg) { 360 seq_puts(m, "crtc:\n"); 361 seq_printf(m, "\twriteback=%d\n", 362 vkms_config_crtc_get_writeback(crtc_cfg)); 363 } 364 365 vkms_config_for_each_encoder(vkmsdev->config, encoder_cfg) 366 seq_puts(m, "encoder\n"); 367 368 vkms_config_for_each_connector(vkmsdev->config, connector_cfg) { 369 seq_puts(m, "connector:\n"); 370 seq_printf(m, "\tstatus=%d\n", 371 vkms_config_connector_get_status(connector_cfg)); 372 } 373 374 return 0; 375} 376 377static const struct drm_debugfs_info vkms_config_debugfs_list[] = { 378 { "vkms_config", vkms_config_show, 0 }, 379}; 380 381void vkms_config_register_debugfs(struct vkms_device *vkms_device) 382{ 383 drm_debugfs_add_files(&vkms_device->drm, vkms_config_debugfs_list, 384 ARRAY_SIZE(vkms_config_debugfs_list)); 385} 386 387struct vkms_config_plane *vkms_config_create_plane(struct vkms_config *config) 388{ 389 struct vkms_config_plane *plane_cfg; 390 391 plane_cfg = kzalloc(sizeof(*plane_cfg), GFP_KERNEL); 392 if (!plane_cfg) 393 return ERR_PTR(-ENOMEM); 394 395 plane_cfg->config = config; 396 plane_cfg->default_pipeline = false; 397 vkms_config_plane_set_type(plane_cfg, DRM_PLANE_TYPE_OVERLAY); 398 xa_init_flags(&plane_cfg->possible_crtcs, XA_FLAGS_ALLOC); 399 400 list_add_tail(&plane_cfg->link, &config->planes); 401 402 return plane_cfg; 403} 404EXPORT_SYMBOL_IF_KUNIT(vkms_config_create_plane); 405 406void vkms_config_destroy_plane(struct vkms_config_plane *plane_cfg) 407{ 408 xa_destroy(&plane_cfg->possible_crtcs); 409 list_del(&plane_cfg->link); 410 kfree(plane_cfg); 411} 412EXPORT_SYMBOL_IF_KUNIT(vkms_config_destroy_plane); 413 414int __must_check vkms_config_plane_attach_crtc(struct vkms_config_plane *plane_cfg, 415 struct vkms_config_crtc *crtc_cfg) 416{ 417 struct vkms_config_crtc *possible_crtc; 418 unsigned long idx = 0; 419 u32 crtc_idx = 0; 420 421 if (plane_cfg->config != crtc_cfg->config) 422 return -EINVAL; 423 424 vkms_config_plane_for_each_possible_crtc(plane_cfg, idx, possible_crtc) { 425 if (possible_crtc == crtc_cfg) 426 return -EEXIST; 427 } 428 429 return xa_alloc(&plane_cfg->possible_crtcs, &crtc_idx, crtc_cfg, 430 xa_limit_32b, GFP_KERNEL); 431} 432EXPORT_SYMBOL_IF_KUNIT(vkms_config_plane_attach_crtc); 433 434void vkms_config_plane_detach_crtc(struct vkms_config_plane *plane_cfg, 435 struct vkms_config_crtc *crtc_cfg) 436{ 437 struct vkms_config_crtc *possible_crtc; 438 unsigned long idx = 0; 439 440 vkms_config_plane_for_each_possible_crtc(plane_cfg, idx, possible_crtc) { 441 if (possible_crtc == crtc_cfg) 442 xa_erase(&plane_cfg->possible_crtcs, idx); 443 } 444} 445EXPORT_SYMBOL_IF_KUNIT(vkms_config_plane_detach_crtc); 446 447struct vkms_config_crtc *vkms_config_create_crtc(struct vkms_config *config) 448{ 449 struct vkms_config_crtc *crtc_cfg; 450 451 crtc_cfg = kzalloc(sizeof(*crtc_cfg), GFP_KERNEL); 452 if (!crtc_cfg) 453 return ERR_PTR(-ENOMEM); 454 455 crtc_cfg->config = config; 456 vkms_config_crtc_set_writeback(crtc_cfg, false); 457 458 list_add_tail(&crtc_cfg->link, &config->crtcs); 459 460 return crtc_cfg; 461} 462EXPORT_SYMBOL_IF_KUNIT(vkms_config_create_crtc); 463 464void vkms_config_destroy_crtc(struct vkms_config *config, 465 struct vkms_config_crtc *crtc_cfg) 466{ 467 struct vkms_config_plane *plane_cfg; 468 struct vkms_config_encoder *encoder_cfg; 469 470 vkms_config_for_each_plane(config, plane_cfg) 471 vkms_config_plane_detach_crtc(plane_cfg, crtc_cfg); 472 473 vkms_config_for_each_encoder(config, encoder_cfg) 474 vkms_config_encoder_detach_crtc(encoder_cfg, crtc_cfg); 475 476 list_del(&crtc_cfg->link); 477 kfree(crtc_cfg); 478} 479EXPORT_SYMBOL_IF_KUNIT(vkms_config_destroy_crtc); 480 481/** 482 * vkms_config_crtc_get_plane() - Return the first attached plane to a CRTC with 483 * the specific type 484 * @config: Configuration containing the CRTC and the plane 485 * @crtc_cfg: Only find planes attached to this CRTC 486 * @type: Plane type to search 487 * 488 * Returns: 489 * The first plane found attached to @crtc_cfg with the type @type. 490 */ 491static struct vkms_config_plane *vkms_config_crtc_get_plane(const struct vkms_config *config, 492 struct vkms_config_crtc *crtc_cfg, 493 enum drm_plane_type type) 494{ 495 struct vkms_config_plane *plane_cfg; 496 struct vkms_config_crtc *possible_crtc; 497 enum drm_plane_type current_type; 498 unsigned long idx = 0; 499 500 vkms_config_for_each_plane(config, plane_cfg) { 501 current_type = vkms_config_plane_get_type(plane_cfg); 502 503 vkms_config_plane_for_each_possible_crtc(plane_cfg, idx, possible_crtc) { 504 if (possible_crtc == crtc_cfg && current_type == type) 505 return plane_cfg; 506 } 507 } 508 509 return NULL; 510} 511 512struct vkms_config_plane *vkms_config_crtc_primary_plane(const struct vkms_config *config, 513 struct vkms_config_crtc *crtc_cfg) 514{ 515 return vkms_config_crtc_get_plane(config, crtc_cfg, DRM_PLANE_TYPE_PRIMARY); 516} 517EXPORT_SYMBOL_IF_KUNIT(vkms_config_crtc_primary_plane); 518 519struct vkms_config_plane *vkms_config_crtc_cursor_plane(const struct vkms_config *config, 520 struct vkms_config_crtc *crtc_cfg) 521{ 522 return vkms_config_crtc_get_plane(config, crtc_cfg, DRM_PLANE_TYPE_CURSOR); 523} 524EXPORT_SYMBOL_IF_KUNIT(vkms_config_crtc_cursor_plane); 525 526struct vkms_config_encoder *vkms_config_create_encoder(struct vkms_config *config) 527{ 528 struct vkms_config_encoder *encoder_cfg; 529 530 encoder_cfg = kzalloc(sizeof(*encoder_cfg), GFP_KERNEL); 531 if (!encoder_cfg) 532 return ERR_PTR(-ENOMEM); 533 534 encoder_cfg->config = config; 535 xa_init_flags(&encoder_cfg->possible_crtcs, XA_FLAGS_ALLOC); 536 537 list_add_tail(&encoder_cfg->link, &config->encoders); 538 539 return encoder_cfg; 540} 541EXPORT_SYMBOL_IF_KUNIT(vkms_config_create_encoder); 542 543void vkms_config_destroy_encoder(struct vkms_config *config, 544 struct vkms_config_encoder *encoder_cfg) 545{ 546 struct vkms_config_connector *connector_cfg; 547 548 vkms_config_for_each_connector(config, connector_cfg) 549 vkms_config_connector_detach_encoder(connector_cfg, encoder_cfg); 550 551 xa_destroy(&encoder_cfg->possible_crtcs); 552 list_del(&encoder_cfg->link); 553 kfree(encoder_cfg); 554} 555EXPORT_SYMBOL_IF_KUNIT(vkms_config_destroy_encoder); 556 557int __must_check vkms_config_encoder_attach_crtc(struct vkms_config_encoder *encoder_cfg, 558 struct vkms_config_crtc *crtc_cfg) 559{ 560 struct vkms_config_crtc *possible_crtc; 561 unsigned long idx = 0; 562 u32 crtc_idx = 0; 563 564 if (encoder_cfg->config != crtc_cfg->config) 565 return -EINVAL; 566 567 vkms_config_encoder_for_each_possible_crtc(encoder_cfg, idx, possible_crtc) { 568 if (possible_crtc == crtc_cfg) 569 return -EEXIST; 570 } 571 572 return xa_alloc(&encoder_cfg->possible_crtcs, &crtc_idx, crtc_cfg, 573 xa_limit_32b, GFP_KERNEL); 574} 575EXPORT_SYMBOL_IF_KUNIT(vkms_config_encoder_attach_crtc); 576 577void vkms_config_encoder_detach_crtc(struct vkms_config_encoder *encoder_cfg, 578 struct vkms_config_crtc *crtc_cfg) 579{ 580 struct vkms_config_crtc *possible_crtc; 581 unsigned long idx = 0; 582 583 vkms_config_encoder_for_each_possible_crtc(encoder_cfg, idx, possible_crtc) { 584 if (possible_crtc == crtc_cfg) 585 xa_erase(&encoder_cfg->possible_crtcs, idx); 586 } 587} 588EXPORT_SYMBOL_IF_KUNIT(vkms_config_encoder_detach_crtc); 589 590struct vkms_config_connector *vkms_config_create_connector(struct vkms_config *config) 591{ 592 struct vkms_config_connector *connector_cfg; 593 594 connector_cfg = kzalloc(sizeof(*connector_cfg), GFP_KERNEL); 595 if (!connector_cfg) 596 return ERR_PTR(-ENOMEM); 597 598 connector_cfg->config = config; 599 connector_cfg->status = connector_status_connected; 600 xa_init_flags(&connector_cfg->possible_encoders, XA_FLAGS_ALLOC); 601 602 list_add_tail(&connector_cfg->link, &config->connectors); 603 604 return connector_cfg; 605} 606EXPORT_SYMBOL_IF_KUNIT(vkms_config_create_connector); 607 608void vkms_config_destroy_connector(struct vkms_config_connector *connector_cfg) 609{ 610 xa_destroy(&connector_cfg->possible_encoders); 611 list_del(&connector_cfg->link); 612 kfree(connector_cfg); 613} 614EXPORT_SYMBOL_IF_KUNIT(vkms_config_destroy_connector); 615 616int __must_check vkms_config_connector_attach_encoder(struct vkms_config_connector *connector_cfg, 617 struct vkms_config_encoder *encoder_cfg) 618{ 619 struct vkms_config_encoder *possible_encoder; 620 unsigned long idx = 0; 621 u32 encoder_idx = 0; 622 623 if (connector_cfg->config != encoder_cfg->config) 624 return -EINVAL; 625 626 vkms_config_connector_for_each_possible_encoder(connector_cfg, idx, 627 possible_encoder) { 628 if (possible_encoder == encoder_cfg) 629 return -EEXIST; 630 } 631 632 return xa_alloc(&connector_cfg->possible_encoders, &encoder_idx, 633 encoder_cfg, xa_limit_32b, GFP_KERNEL); 634} 635EXPORT_SYMBOL_IF_KUNIT(vkms_config_connector_attach_encoder); 636 637void vkms_config_connector_detach_encoder(struct vkms_config_connector *connector_cfg, 638 struct vkms_config_encoder *encoder_cfg) 639{ 640 struct vkms_config_encoder *possible_encoder; 641 unsigned long idx = 0; 642 643 vkms_config_connector_for_each_possible_encoder(connector_cfg, idx, 644 possible_encoder) { 645 if (possible_encoder == encoder_cfg) 646 xa_erase(&connector_cfg->possible_encoders, idx); 647 } 648} 649EXPORT_SYMBOL_IF_KUNIT(vkms_config_connector_detach_encoder);
~/
Read-only file preview.