drm/modes: add connector reference counting. (v2)
This uses the previous changes to add reference counts to drm connector objects. v2: move fbdev changes to their own patch. add some kerneldoc Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Reviewed-by: Daniel Stone <daniels@collabora.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
parent
e76d399f21
commit
b164d31f50
|
@ -156,6 +156,7 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
|
||||||
state->connector_states[i]);
|
state->connector_states[i]);
|
||||||
state->connectors[i] = NULL;
|
state->connectors[i] = NULL;
|
||||||
state->connector_states[i] = NULL;
|
state->connector_states[i] = NULL;
|
||||||
|
drm_connector_unreference(connector);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < config->num_crtc; i++) {
|
for (i = 0; i < config->num_crtc; i++) {
|
||||||
|
@ -932,6 +933,7 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
|
||||||
if (!connector_state)
|
if (!connector_state)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
drm_connector_reference(connector);
|
||||||
state->connector_states[index] = connector_state;
|
state->connector_states[index] = connector_state;
|
||||||
state->connectors[index] = connector;
|
state->connectors[index] = connector;
|
||||||
connector_state->state = state;
|
connector_state->state = state;
|
||||||
|
@ -1622,12 +1624,19 @@ retry:
|
||||||
}
|
}
|
||||||
|
|
||||||
obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_ANY);
|
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;
|
ret = -ENOENT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_user(count_props, count_props_ptr + copied_objs)) {
|
if (get_user(count_props, count_props_ptr + copied_objs)) {
|
||||||
|
drm_mode_object_unreference(obj);
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -1640,12 +1649,14 @@ retry:
|
||||||
struct drm_property *prop;
|
struct drm_property *prop;
|
||||||
|
|
||||||
if (get_user(prop_id, props_ptr + copied_props)) {
|
if (get_user(prop_id, props_ptr + copied_props)) {
|
||||||
|
drm_mode_object_unreference(obj);
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
prop = drm_property_find(dev, prop_id);
|
prop = drm_property_find(dev, prop_id);
|
||||||
if (!prop) {
|
if (!prop) {
|
||||||
|
drm_mode_object_unreference(obj);
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -1653,13 +1664,16 @@ retry:
|
||||||
if (copy_from_user(&prop_value,
|
if (copy_from_user(&prop_value,
|
||||||
prop_values_ptr + copied_props,
|
prop_values_ptr + copied_props,
|
||||||
sizeof(prop_value))) {
|
sizeof(prop_value))) {
|
||||||
|
drm_mode_object_unreference(obj);
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = atomic_set_prop(state, obj, prop, prop_value);
|
ret = atomic_set_prop(state, obj, prop, prop_value);
|
||||||
if (ret)
|
if (ret) {
|
||||||
|
drm_mode_object_unreference(obj);
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
copied_props++;
|
copied_props++;
|
||||||
}
|
}
|
||||||
|
@ -1670,6 +1684,7 @@ retry:
|
||||||
plane_mask |= (1 << drm_plane_index(plane));
|
plane_mask |= (1 << drm_plane_index(plane));
|
||||||
plane->old_fb = plane->fb;
|
plane->old_fb = plane->fb;
|
||||||
}
|
}
|
||||||
|
drm_mode_object_unreference(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
|
if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
|
||||||
|
|
|
@ -864,6 +864,16 @@ static void drm_connector_get_cmdline_mode(struct drm_connector *connector)
|
||||||
mode->interlace ? " interlaced" : "");
|
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
|
* drm_connector_init - Init a preallocated connector
|
||||||
* @dev: DRM device
|
* @dev: DRM device
|
||||||
|
@ -889,7 +899,9 @@ int drm_connector_init(struct drm_device *dev,
|
||||||
|
|
||||||
drm_modeset_lock_all(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)
|
if (ret)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
|
@ -2137,7 +2149,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
|
||||||
|
|
||||||
mutex_lock(&dev->mode_config.mutex);
|
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) {
|
if (!connector) {
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
@ -2221,6 +2233,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
|
||||||
out:
|
out:
|
||||||
drm_modeset_unlock(&dev->mode_config.connection_mutex);
|
drm_modeset_unlock(&dev->mode_config.connection_mutex);
|
||||||
|
|
||||||
|
drm_connector_unreference(connector);
|
||||||
out_unlock:
|
out_unlock:
|
||||||
mutex_unlock(&dev->mode_config.mutex);
|
mutex_unlock(&dev->mode_config.mutex);
|
||||||
|
|
||||||
|
@ -2865,13 +2878,14 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < crtc_req->count_connectors; i++) {
|
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;
|
set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr;
|
||||||
if (get_user(out_id, &set_connectors_ptr[i])) {
|
if (get_user(out_id, &set_connectors_ptr[i])) {
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
connector = drm_connector_find(dev, out_id);
|
connector = drm_connector_lookup(dev, out_id);
|
||||||
if (!connector) {
|
if (!connector) {
|
||||||
DRM_DEBUG_KMS("Connector id %d unknown\n",
|
DRM_DEBUG_KMS("Connector id %d unknown\n",
|
||||||
out_id);
|
out_id);
|
||||||
|
@ -2899,6 +2913,12 @@ out:
|
||||||
if (fb)
|
if (fb)
|
||||||
drm_framebuffer_unreference(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);
|
kfree(connector_set);
|
||||||
drm_mode_destroy(dev, mode);
|
drm_mode_destroy(dev, mode);
|
||||||
drm_modeset_unlock_all(dev);
|
drm_modeset_unlock_all(dev);
|
||||||
|
@ -4989,7 +5009,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
|
||||||
property = obj_to_property(prop_obj);
|
property = obj_to_property(prop_obj);
|
||||||
|
|
||||||
if (!drm_property_change_valid_get(property, arg->value, &ref))
|
if (!drm_property_change_valid_get(property, arg->value, &ref))
|
||||||
goto out;
|
goto out_unref;
|
||||||
|
|
||||||
switch (arg_obj->type) {
|
switch (arg_obj->type) {
|
||||||
case DRM_MODE_OBJECT_CONNECTOR:
|
case DRM_MODE_OBJECT_CONNECTOR:
|
||||||
|
|
|
@ -2571,7 +2571,15 @@ static inline struct drm_encoder *drm_encoder_find(struct drm_device *dev,
|
||||||
return mo ? obj_to_encoder(mo) : NULL;
|
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)
|
uint32_t id)
|
||||||
{
|
{
|
||||||
struct drm_mode_object *mo;
|
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);
|
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. */
|
/* Plane list iterator for legacy (overlay only) planes. */
|
||||||
#define drm_for_each_legacy_plane(plane, dev) \
|
#define drm_for_each_legacy_plane(plane, dev) \
|
||||||
list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) \
|
list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) \
|
||||||
|
|
Loading…
Reference in New Issue