Add fields to drm_crtc, drm_encoder, drm_connector, and drm_plane that keep track of which render node owns it. Assign ownership when resource is added and revoke it when resource is destroyed. Do not allow creation of a node that tries to claim resources that are already in use by another node. v2: - track planes too Signed-off-by: Ilija Hadzic <ihadzic@xxxxxxxxxxxxxxxxxxxxxx> --- drivers/gpu/drm/drm_crtc.c | 4 ++ drivers/gpu/drm/drm_stub.c | 111 ++++++++++++++++++++++++++++++++++++++++++++ include/drm/drm_crtc.h | 5 ++ 3 files changed, 120 insertions(+), 0 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index cce3d25..45a2925 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -375,6 +375,7 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, crtc->dev = dev; crtc->funcs = funcs; + crtc->render_node_owner = -1; mutex_lock(&dev->mode_config.mutex); @@ -483,6 +484,7 @@ int drm_connector_init(struct drm_device *dev, connector->dev = dev; connector->funcs = funcs; + connector->render_node_owner = -1; connector->connector_type = connector_type; connector->connector_type_id = ++drm_connector_enum_list[connector_type].count; /* TODO */ @@ -553,6 +555,7 @@ int drm_encoder_init(struct drm_device *dev, if (ret) goto out; + encoder->render_node_owner = -1; encoder->dev = dev; encoder->encoder_type = encoder_type; encoder->funcs = funcs; @@ -594,6 +597,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, plane->dev = dev; plane->funcs = funcs; + plane->render_node_owner = -1; plane->format_types = kmalloc(sizeof(uint32_t) * format_count, GFP_KERNEL); if (!plane->format_types) { diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 340a7e4..13ff4c8 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -447,6 +447,95 @@ static int drm_get_render_node_resources(struct drm_device *dev, return 0; } +static int *drm_get_render_node_owner(struct drm_device *dev, + uint32_t id, uint32_t type) +{ + struct drm_mode_object *obj; + struct drm_crtc *crtc; + struct drm_encoder *encoder; + struct drm_connector *connector; + struct drm_plane *plane; + + obj = drm_mode_object_find(dev, id, type); + if (!obj) + return NULL; + switch (type) { + case DRM_MODE_OBJECT_CRTC: + crtc = container_of(obj, struct drm_crtc, base); + return &crtc->render_node_owner; + case DRM_MODE_OBJECT_ENCODER: + encoder = container_of(obj, struct drm_encoder, base); + return &encoder->render_node_owner; + case DRM_MODE_OBJECT_CONNECTOR: + connector = container_of(obj, struct drm_connector, base); + return &connector->render_node_owner; + case DRM_MODE_OBJECT_PLANE: + plane = container_of(obj, struct drm_plane, base); + return &plane->render_node_owner; + + default: + return NULL; + } +} + +static void drm_release_render_node_resources(struct drm_device *dev, + uint32_t *id_list, + int *resource_count, + int minor) +{ + int *render_node_owner; + int s, e, i, j; + + for (e = 0, j = 0; j < DRM_RN_NUM_EXP_TYPES; j++) { + s = e; + e += resource_count[j]; + for (i = s; i < e; i++) { + render_node_owner = + drm_get_render_node_owner(dev, id_list[i], + expected_type_list[j]); + if (render_node_owner && + *render_node_owner == minor) + *render_node_owner = -1; + } + } +} + +static int drm_claim_render_node_resources(struct drm_device *dev, + uint32_t *id_list, + int *resource_count, + int minor) +{ + int *render_node_owner; + int s, e, i, j; + int ret = 0; + + for (e = 0, j = 0; j < DRM_RN_NUM_EXP_TYPES; j++) { + s = e; + e += resource_count[j]; + for (i = s; i < e; i++) { + render_node_owner = + drm_get_render_node_owner(dev, id_list[i], + expected_type_list[j]); + if (!render_node_owner) { + /* list was validated, not supposed to fail */ + WARN_ON(1); + ret = -EFAULT; + goto out_release; + } + if (*render_node_owner != -1) { + ret = -EBUSY; + goto out_release; + } + *render_node_owner = minor; + } + } + return ret; + +out_release: + drm_release_render_node_resources(dev, id_list, resource_count, minor); + return ret; +} + int drm_create_render_node(struct drm_device *dev, struct drm_minor **minor_p) { int ret; @@ -475,10 +564,19 @@ int drm_destroy_render_node(struct drm_device *dev, int index) list_for_each_entry_safe(node, tmp, &dev->render_node_list, list) { if (node->minor->index == index) { struct drm_mode_group *group; + int resource_count[DRM_RN_NUM_EXP_TYPES]; + if (node->minor->open_count) return -EBUSY; group = &node->minor->mode_group; list_del(&node->list); + resource_count[0] = group->num_crtcs; + resource_count[1] = group->num_encoders; + resource_count[2] = group->num_connectors; + resource_count[3] = group->num_planes; + drm_release_render_node_resources(dev, group->id_list, + resource_count, + node->minor->index); drm_put_minor(&node->minor); drm_mode_group_fini(group); kfree(node); @@ -494,8 +592,17 @@ void drm_destroy_all_render_nodes(struct drm_device *dev) list_for_each_entry_safe(node, tmp, &dev->render_node_list, list) { struct drm_mode_group *group; + int resource_count[DRM_RN_NUM_EXP_TYPES]; + group = &node->minor->mode_group; list_del(&node->list); + resource_count[0] = group->num_crtcs; + resource_count[1] = group->num_encoders; + resource_count[2] = group->num_connectors; + resource_count[3] = group->num_planes; + drm_release_render_node_resources(dev, group->id_list, + resource_count, + node->minor->index); drm_put_minor(&node->minor); drm_mode_group_fini(group); kfree(node); @@ -652,6 +759,10 @@ int drm_render_node_create_ioctl(struct drm_device *dev, void *data, resource_count); if (ret) goto out_del; + ret = drm_claim_render_node_resources(dev, id_list, resource_count, + new_minor->index); + if (ret) + goto out_del; new_minor->mode_group.num_crtcs = args->num_crtc; new_minor->mode_group.num_encoders = args->num_encoder; new_minor->mode_group.num_connectors = args->num_connector; diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 7c1227b..c38635d 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -374,6 +374,7 @@ struct drm_crtc { struct drm_framebuffer *fb; bool enabled; + int render_node_owner; /* Requested mode from modesetting. */ struct drm_display_mode mode; @@ -479,6 +480,8 @@ struct drm_encoder { uint32_t possible_crtcs; uint32_t possible_clones; + int render_node_owner; + struct drm_crtc *crtc; const struct drm_encoder_funcs *funcs; void *helper_private; @@ -556,6 +559,7 @@ struct drm_connector { struct list_head modes; /* list of modes on this connector */ enum drm_connector_status status; + int render_node_owner; /* these are modes added by probing with DDC or the BIOS */ struct list_head probed_modes; @@ -641,6 +645,7 @@ struct drm_plane { uint16_t *gamma_store; bool enabled; + int render_node_owner; const struct drm_plane_funcs *funcs; void *helper_private; -- 1.7.8.5 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel