diff options
Diffstat (limited to 'drivers/gpu/drm/vkms/vkms_config.c')
| -rw-r--r-- | drivers/gpu/drm/vkms/vkms_config.c | 154 |
1 files changed, 140 insertions, 14 deletions
diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c index d195db770fae..458385413648 100644 --- a/drivers/gpu/drm/vkms/vkms_config.c +++ b/drivers/gpu/drm/vkms/vkms_config.c @@ -52,13 +52,20 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor, goto err_alloc; vkms_config_crtc_set_writeback(crtc_cfg, enable_writeback); + if (vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg)) + goto err_alloc; + if (enable_overlay) { for (n = 0; n < NUM_OVERLAY_PLANES; n++) { plane_cfg = vkms_config_create_plane(config); if (IS_ERR(plane_cfg)) goto err_alloc; + vkms_config_plane_set_type(plane_cfg, DRM_PLANE_TYPE_OVERLAY); + + if (vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg)) + goto err_alloc; } } @@ -66,7 +73,11 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor, plane_cfg = vkms_config_create_plane(config); if (IS_ERR(plane_cfg)) goto err_alloc; + vkms_config_plane_set_type(plane_cfg, DRM_PLANE_TYPE_CURSOR); + + if (vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg)) + goto err_alloc; } return config; @@ -107,7 +118,8 @@ static bool valid_plane_number(const struct vkms_config *config) return true; } -static bool valid_plane_type(const struct vkms_config *config) +static bool valid_planes_for_crtc(const struct vkms_config *config, + struct vkms_config_crtc *crtc_cfg) { struct drm_device *dev = config->dev ? &config->dev->drm : NULL; struct vkms_config_plane *plane_cfg; @@ -115,24 +127,31 @@ static bool valid_plane_type(const struct vkms_config *config) bool has_cursor_plane = false; vkms_config_for_each_plane(config, plane_cfg) { + struct vkms_config_crtc *possible_crtc; + unsigned long idx = 0; enum drm_plane_type type; type = vkms_config_plane_get_type(plane_cfg); - if (type == DRM_PLANE_TYPE_PRIMARY) { - if (has_primary_plane) { - drm_info(dev, "Multiple primary planes\n"); - return false; - } + vkms_config_plane_for_each_possible_crtc(plane_cfg, idx, possible_crtc) { + if (possible_crtc != crtc_cfg) + continue; - has_primary_plane = true; - } else if (type == DRM_PLANE_TYPE_CURSOR) { - if (has_cursor_plane) { - drm_info(dev, "Multiple cursor planes\n"); - return false; - } + if (type == DRM_PLANE_TYPE_PRIMARY) { + if (has_primary_plane) { + drm_info(dev, "Multiple primary planes\n"); + return false; + } - has_cursor_plane = true; + has_primary_plane = true; + } else if (type == DRM_PLANE_TYPE_CURSOR) { + if (has_cursor_plane) { + drm_info(dev, "Multiple cursor planes\n"); + return false; + } + + has_cursor_plane = true; + } } } @@ -144,6 +163,21 @@ static bool valid_plane_type(const struct vkms_config *config) return true; } +static bool valid_plane_possible_crtcs(const struct vkms_config *config) +{ + struct drm_device *dev = config->dev ? &config->dev->drm : NULL; + struct vkms_config_plane *plane_cfg; + + vkms_config_for_each_plane(config, plane_cfg) { + if (xa_empty(&plane_cfg->possible_crtcs)) { + drm_info(dev, "All planes must have at least one possible CRTC\n"); + return false; + } + } + + return true; +} + static bool valid_crtc_number(const struct vkms_config *config) { struct drm_device *dev = config->dev ? &config->dev->drm : NULL; @@ -160,15 +194,22 @@ static bool valid_crtc_number(const struct vkms_config *config) bool vkms_config_is_valid(const struct vkms_config *config) { + struct vkms_config_crtc *crtc_cfg; + if (!valid_plane_number(config)) return false; if (!valid_crtc_number(config)) return false; - if (!valid_plane_type(config)) + if (!valid_plane_possible_crtcs(config)) return false; + vkms_config_for_each_crtc(config, crtc_cfg) { + if (!valid_planes_for_crtc(config, crtc_cfg)) + return false; + } + return true; } EXPORT_SYMBOL_IF_KUNIT(vkms_config_is_valid); @@ -220,6 +261,7 @@ struct vkms_config_plane *vkms_config_create_plane(struct vkms_config *config) plane_cfg->config = config; vkms_config_plane_set_type(plane_cfg, DRM_PLANE_TYPE_OVERLAY); + xa_init_flags(&plane_cfg->possible_crtcs, XA_FLAGS_ALLOC); list_add_tail(&plane_cfg->link, &config->planes); @@ -229,11 +271,45 @@ EXPORT_SYMBOL_IF_KUNIT(vkms_config_create_plane); void vkms_config_destroy_plane(struct vkms_config_plane *plane_cfg) { + xa_destroy(&plane_cfg->possible_crtcs); list_del(&plane_cfg->link); kfree(plane_cfg); } EXPORT_SYMBOL_IF_KUNIT(vkms_config_destroy_plane); +int __must_check vkms_config_plane_attach_crtc(struct vkms_config_plane *plane_cfg, + struct vkms_config_crtc *crtc_cfg) +{ + struct vkms_config_crtc *possible_crtc; + unsigned long idx = 0; + u32 crtc_idx = 0; + + if (plane_cfg->config != crtc_cfg->config) + return -EINVAL; + + vkms_config_plane_for_each_possible_crtc(plane_cfg, idx, possible_crtc) { + if (possible_crtc == crtc_cfg) + return -EEXIST; + } + + return xa_alloc(&plane_cfg->possible_crtcs, &crtc_idx, crtc_cfg, + xa_limit_32b, GFP_KERNEL); +} +EXPORT_SYMBOL_IF_KUNIT(vkms_config_plane_attach_crtc); + +void vkms_config_plane_detach_crtc(struct vkms_config_plane *plane_cfg, + struct vkms_config_crtc *crtc_cfg) +{ + struct vkms_config_crtc *possible_crtc; + unsigned long idx = 0; + + vkms_config_plane_for_each_possible_crtc(plane_cfg, idx, possible_crtc) { + if (possible_crtc == crtc_cfg) + xa_erase(&plane_cfg->possible_crtcs, idx); + } +} +EXPORT_SYMBOL_IF_KUNIT(vkms_config_plane_detach_crtc); + struct vkms_config_crtc *vkms_config_create_crtc(struct vkms_config *config) { struct vkms_config_crtc *crtc_cfg; @@ -254,7 +330,57 @@ EXPORT_SYMBOL_IF_KUNIT(vkms_config_create_crtc); void vkms_config_destroy_crtc(struct vkms_config *config, struct vkms_config_crtc *crtc_cfg) { + struct vkms_config_plane *plane_cfg; + + vkms_config_for_each_plane(config, plane_cfg) + vkms_config_plane_detach_crtc(plane_cfg, crtc_cfg); + list_del(&crtc_cfg->link); kfree(crtc_cfg); } EXPORT_SYMBOL_IF_KUNIT(vkms_config_destroy_crtc); + +/** + * vkms_config_crtc_get_plane() - Return the first attached plane to a CRTC with + * the specific type + * @config: Configuration containing the CRTC and the plane + * @crtc_cfg: Only find planes attached to this CRTC + * @type: Plane type to search + * + * Returns: + * The first plane found attached to @crtc_cfg with the type @type. + */ +static struct vkms_config_plane *vkms_config_crtc_get_plane(const struct vkms_config *config, + struct vkms_config_crtc *crtc_cfg, + enum drm_plane_type type) +{ + struct vkms_config_plane *plane_cfg; + struct vkms_config_crtc *possible_crtc; + enum drm_plane_type current_type; + unsigned long idx = 0; + + vkms_config_for_each_plane(config, plane_cfg) { + current_type = vkms_config_plane_get_type(plane_cfg); + + vkms_config_plane_for_each_possible_crtc(plane_cfg, idx, possible_crtc) { + if (possible_crtc == crtc_cfg && current_type == type) + return plane_cfg; + } + } + + return NULL; +} + +struct vkms_config_plane *vkms_config_crtc_primary_plane(const struct vkms_config *config, + struct vkms_config_crtc *crtc_cfg) +{ + return vkms_config_crtc_get_plane(config, crtc_cfg, DRM_PLANE_TYPE_PRIMARY); +} +EXPORT_SYMBOL_IF_KUNIT(vkms_config_crtc_primary_plane); + +struct vkms_config_plane *vkms_config_crtc_cursor_plane(const struct vkms_config *config, + struct vkms_config_crtc *crtc_cfg) +{ + return vkms_config_crtc_get_plane(config, crtc_cfg, DRM_PLANE_TYPE_CURSOR); +} +EXPORT_SYMBOL_IF_KUNIT(vkms_config_crtc_cursor_plane); |
