From: Dave Airlie <airl...@redhat.com>

This uses the previous changes to add reference counts
to drm connector objects.

v2: move fbdev changes to their own patch.
add some kerneldoc
Signed-off-by: Dave Airlie <airlied at redhat.com>
---
 drivers/gpu/drm/drm_atomic.c | 19 +++++++++++++++++--
 drivers/gpu/drm/drm_crtc.c   | 28 ++++++++++++++++++++++++----
 include/drm/drm_crtc.h       | 32 +++++++++++++++++++++++++++++++-
 3 files changed, 72 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 8ee1db8..9d5e3c8 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -154,6 +154,7 @@ void drm_atomic_state_default_clear(struct drm_atomic_state 
*state)
                                                       
state->connector_states[i]);
                state->connectors[i] = NULL;
                state->connector_states[i] = NULL;
+               drm_connector_unreference(connector);
        }

        for (i = 0; i < config->num_crtc; i++) {
@@ -924,6 +925,7 @@ drm_atomic_get_connector_state(struct drm_atomic_state 
*state,
        if (!connector_state)
                return ERR_PTR(-ENOMEM);

+       drm_connector_reference(connector);
        state->connector_states[index] = connector_state;
        state->connectors[index] = connector;
        connector_state->state = state;
@@ -1614,12 +1616,19 @@ retry:
                }

                obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_ANY);
-               if (!obj || !obj->properties) {
+               if (!obj) {
+                       ret = -ENOENT;
+                       goto out;
+               }
+
+               if (!obj->properties) {
+                       drm_mode_object_unreference(obj);
                        ret = -ENOENT;
                        goto out;
                }

                if (get_user(count_props, count_props_ptr + copied_objs)) {
+                       drm_mode_object_unreference(obj);
                        ret = -EFAULT;
                        goto out;
                }
@@ -1632,12 +1641,14 @@ retry:
                        struct drm_property *prop;

                        if (get_user(prop_id, props_ptr + copied_props)) {
+                               drm_mode_object_unreference(obj);
                                ret = -EFAULT;
                                goto out;
                        }

                        prop = drm_property_find(dev, prop_id);
                        if (!prop) {
+                               drm_mode_object_unreference(obj);
                                ret = -ENOENT;
                                goto out;
                        }
@@ -1645,13 +1656,16 @@ retry:
                        if (copy_from_user(&prop_value,
                                           prop_values_ptr + copied_props,
                                           sizeof(prop_value))) {
+                               drm_mode_object_unreference(obj);
                                ret = -EFAULT;
                                goto out;
                        }

                        ret = atomic_set_prop(state, obj, prop, prop_value);
-                       if (ret)
+                       if (ret) {
+                               drm_mode_object_unreference(obj);
                                goto out;
+                       }

                        copied_props++;
                }
@@ -1662,6 +1676,7 @@ retry:
                        plane_mask |= (1 << drm_plane_index(plane));
                        plane->old_fb = plane->fb;
                }
+               drm_mode_object_unreference(obj);
        }

        if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 4e5b015..a78e202 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -862,6 +862,16 @@ static void drm_connector_get_cmdline_mode(struct 
drm_connector *connector)
                      mode->interlace ?  " interlaced" : "");
 }

+static void drm_connector_free(struct kref *kref)
+{
+       struct drm_connector *connector =
+               container_of(kref, struct drm_connector, base.refcount);
+       struct drm_device *dev = connector->dev;
+
+       drm_mode_object_unregister(dev, &connector->base);
+       connector->funcs->destroy(connector);
+}
+
 /**
  * drm_connector_init - Init a preallocated connector
  * @dev: DRM device
@@ -887,7 +897,9 @@ int drm_connector_init(struct drm_device *dev,

        drm_modeset_lock_all(dev);

-       ret = drm_mode_object_get_reg(dev, &connector->base, 
DRM_MODE_OBJECT_CONNECTOR, false, NULL);
+       ret = drm_mode_object_get_reg(dev, &connector->base,
+                                     DRM_MODE_OBJECT_CONNECTOR,
+                                     false, drm_connector_free);
        if (ret)
                goto out_unlock;

@@ -2147,7 +2159,7 @@ int drm_mode_getconnector(struct drm_device *dev, void 
*data,

        mutex_lock(&dev->mode_config.mutex);

-       connector = drm_connector_find(dev, out_resp->connector_id);
+       connector = drm_connector_lookup(dev, out_resp->connector_id);
        if (!connector) {
                ret = -ENOENT;
                goto out_unlock;
@@ -2231,6 +2243,7 @@ int drm_mode_getconnector(struct drm_device *dev, void 
*data,
 out:
        drm_modeset_unlock(&dev->mode_config.connection_mutex);

+       drm_connector_unreference(connector);
 out_unlock:
        mutex_unlock(&dev->mode_config.mutex);

@@ -2875,13 +2888,14 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
                }

                for (i = 0; i < crtc_req->count_connectors; i++) {
+                       connector_set[i] = NULL;
                        set_connectors_ptr = (uint32_t __user *)(unsigned 
long)crtc_req->set_connectors_ptr;
                        if (get_user(out_id, &set_connectors_ptr[i])) {
                                ret = -EFAULT;
                                goto out;
                        }

-                       connector = drm_connector_find(dev, out_id);
+                       connector = drm_connector_lookup(dev, out_id);
                        if (!connector) {
                                DRM_DEBUG_KMS("Connector id %d unknown\n",
                                                out_id);
@@ -2909,6 +2923,12 @@ out:
        if (fb)
                drm_framebuffer_unreference(fb);

+       if (connector_set) {
+               for (i = 0; i < crtc_req->count_connectors; i++) {
+                       if (connector_set[i])
+                               drm_connector_unreference(connector_set[i]);
+               }
+       }
        kfree(connector_set);
        drm_mode_destroy(dev, mode);
        drm_modeset_unlock_all(dev);
@@ -4999,7 +5019,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device 
*dev, void *data,
        property = obj_to_property(prop_obj);

        if (!drm_property_change_valid_get(property, arg->value, &ref))
-               goto out;
+               goto out_unref;

        switch (arg_obj->type) {
        case DRM_MODE_OBJECT_CONNECTOR:
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 297e527..16a98d4 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -2571,7 +2571,15 @@ static inline struct drm_encoder 
*drm_encoder_find(struct drm_device *dev,
        return mo ? obj_to_encoder(mo) : NULL;
 }

-static inline struct drm_connector *drm_connector_find(struct drm_device *dev,
+/*
+ * drm_connector_lookup - lookup connector object
+ * @dev: DRM device
+ * @id: connector object id
+ *
+ * This function looks up the connector object specified by id
+ * add takes a reference to it.
+ */
+static inline struct drm_connector *drm_connector_lookup(struct drm_device 
*dev,
                uint32_t id)
 {
        struct drm_mode_object *mo;
@@ -2639,6 +2647,28 @@ static inline uint32_t 
drm_framebuffer_read_refcount(struct drm_framebuffer *fb)
        return atomic_read(&fb->base.refcount.refcount);
 }

+/*
+ * drm_connector_reference - incr the connector refcnt
+ * @connector: connector
+ *
+ * This function increments the connector's refcount.
+ */
+static inline void drm_connector_reference(struct drm_connector *connector)
+{
+       drm_mode_object_reference(&connector->base);
+}
+
+/**
+ * drm_connector_unreference - unref a connector
+ * @connector: connector to unref
+ *
+ * This function decrements the connector's refcount and frees it if it drops 
to zero.
+ */
+static inline void drm_connector_unreference(struct drm_connector *connector)
+{
+       drm_mode_object_unreference(&connector->base);
+}
+
 /* Plane list iterator for legacy (overlay only) planes. */
 #define drm_for_each_legacy_plane(plane, dev) \
        list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) \
-- 
2.5.5

Reply via email to