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 at research.bell-labs.com>
---
 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

Reply via email to