diff options
Diffstat (limited to 'drivers/gpu/drm/drm_mode_object.c')
-rw-r--r-- | drivers/gpu/drm/drm_mode_object.c | 192 |
1 files changed, 143 insertions, 49 deletions
diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c index da9a9adbcc98..ce4d2fb32810 100644 --- a/drivers/gpu/drm/drm_mode_object.c +++ b/drivers/gpu/drm/drm_mode_object.c @@ -104,7 +104,27 @@ void drm_mode_object_unregister(struct drm_device *dev, mutex_unlock(&dev->mode_config.idr_mutex); } +/** + * drm_lease_required - check types which must be leased to be used + * @type: type of object + * + * Returns whether the provided type of drm_mode_object must + * be owned or leased to be used by a process. + */ +bool drm_mode_object_lease_required(uint32_t type) +{ + switch(type) { + case DRM_MODE_OBJECT_CRTC: + case DRM_MODE_OBJECT_CONNECTOR: + case DRM_MODE_OBJECT_PLANE: + return true; + default: + return false; + } +} + struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev, + struct drm_file *file_priv, uint32_t id, uint32_t type) { struct drm_mode_object *obj = NULL; @@ -116,6 +136,10 @@ struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev, if (obj && obj->id != id) obj = NULL; + if (obj && drm_mode_object_lease_required(obj->type) && + !_drm_lease_held(file_priv, obj->id)) + obj = NULL; + if (obj && obj->free_cb) { if (!kref_get_unless_zero(&obj->refcount)) obj = NULL; @@ -128,6 +152,7 @@ struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev, /** * drm_mode_object_find - look up a drm object with static lifetime * @dev: drm device + * @file_priv: drm file * @id: id of the mode object * @type: type of the mode object * @@ -136,11 +161,12 @@ struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev, * by callind drm_mode_object_put(). */ struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, + struct drm_file *file_priv, uint32_t id, uint32_t type) { struct drm_mode_object *obj = NULL; - obj = __drm_mode_object_find(dev, id, type); + obj = __drm_mode_object_find(dev, file_priv, id, type); return obj; } EXPORT_SYMBOL(drm_mode_object_find); @@ -233,6 +259,9 @@ int drm_object_property_set_value(struct drm_mode_object *obj, { int i; + WARN_ON(drm_drv_uses_atomic_modeset(property->dev) && + !(property->flags & DRM_MODE_PROP_IMMUTABLE)); + for (i = 0; i < obj->properties->count; i++) { if (obj->properties->properties[i] == property) { obj->properties->values[i] = val; @@ -244,6 +273,31 @@ int drm_object_property_set_value(struct drm_mode_object *obj, } EXPORT_SYMBOL(drm_object_property_set_value); +static int __drm_object_property_get_value(struct drm_mode_object *obj, + struct drm_property *property, + uint64_t *val) +{ + int i; + + /* read-only properties bypass atomic mechanism and still store + * their value in obj->properties->values[].. mostly to avoid + * having to deal w/ EDID and similar props in atomic paths: + */ + if (drm_drv_uses_atomic_modeset(property->dev) && + !(property->flags & DRM_MODE_PROP_IMMUTABLE)) + return drm_atomic_get_property(obj, property, val); + + for (i = 0; i < obj->properties->count; i++) { + if (obj->properties->properties[i] == property) { + *val = obj->properties->values[i]; + return 0; + } + + } + + return -EINVAL; +} + /** * drm_object_property_get_value - retrieve the value of a property * @obj: drm mode object to get property value from @@ -264,25 +318,9 @@ EXPORT_SYMBOL(drm_object_property_set_value); int drm_object_property_get_value(struct drm_mode_object *obj, struct drm_property *property, uint64_t *val) { - int i; - - /* read-only properties bypass atomic mechanism and still store - * their value in obj->properties->values[].. mostly to avoid - * having to deal w/ EDID and similar props in atomic paths: - */ - if (drm_drv_uses_atomic_modeset(property->dev) && - !(property->flags & DRM_MODE_PROP_IMMUTABLE)) - return drm_atomic_get_property(obj, property, val); - - for (i = 0; i < obj->properties->count; i++) { - if (obj->properties->properties[i] == property) { - *val = obj->properties->values[i]; - return 0; - } - - } + WARN_ON(drm_drv_uses_atomic_modeset(property->dev)); - return -EINVAL; + return __drm_object_property_get_value(obj, property, val); } EXPORT_SYMBOL(drm_object_property_get_value); @@ -302,7 +340,7 @@ int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic, continue; if (*arg_count_props > count) { - ret = drm_object_property_get_value(obj, prop, &val); + ret = __drm_object_property_get_value(obj, prop, &val); if (ret) return ret; @@ -347,7 +385,7 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, drm_modeset_lock_all(dev); - obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); + obj = drm_mode_object_find(dev, file_priv, arg->obj_id, arg->obj_type); if (!obj) { ret = -ENOENT; goto out; @@ -381,6 +419,83 @@ struct drm_property *drm_mode_obj_find_prop_id(struct drm_mode_object *obj, return NULL; } +static int set_property_legacy(struct drm_mode_object *obj, + struct drm_property *prop, + uint64_t prop_value) +{ + struct drm_device *dev = prop->dev; + struct drm_mode_object *ref; + int ret = -EINVAL; + + if (!drm_property_change_valid_get(prop, prop_value, &ref)) + return -EINVAL; + + drm_modeset_lock_all(dev); + switch (obj->type) { + case DRM_MODE_OBJECT_CONNECTOR: + ret = drm_mode_connector_set_obj_prop(obj, prop, + prop_value); + break; + case DRM_MODE_OBJECT_CRTC: + ret = drm_mode_crtc_set_obj_prop(obj, prop, prop_value); + break; + case DRM_MODE_OBJECT_PLANE: + ret = drm_mode_plane_set_obj_prop(obj_to_plane(obj), + prop, prop_value); + break; + } + drm_property_change_valid_put(prop, ref); + drm_modeset_unlock_all(dev); + + return ret; +} + +static int set_property_atomic(struct drm_mode_object *obj, + struct drm_property *prop, + uint64_t prop_value) +{ + struct drm_device *dev = prop->dev; + struct drm_atomic_state *state; + struct drm_modeset_acquire_ctx ctx; + int ret; + + drm_modeset_acquire_init(&ctx, 0); + + state = drm_atomic_state_alloc(dev); + if (!state) + return -ENOMEM; + state->acquire_ctx = &ctx; +retry: + if (prop == state->dev->mode_config.dpms_property) { + if (obj->type != DRM_MODE_OBJECT_CONNECTOR) { + ret = -EINVAL; + goto out; + } + + ret = drm_atomic_connector_commit_dpms(state, + obj_to_connector(obj), + prop_value); + } else { + ret = drm_atomic_set_property(state, obj, prop, prop_value); + if (ret) + goto out; + ret = drm_atomic_commit(state); + } +out: + if (ret == -EDEADLK) { + drm_atomic_state_clear(state); + drm_modeset_backoff(&ctx); + goto retry; + } + + drm_atomic_state_put(state); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + + return ret; +} + int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -388,18 +503,13 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, struct drm_mode_object *arg_obj; struct drm_property *property; int ret = -EINVAL; - struct drm_mode_object *ref; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - drm_modeset_lock_all(dev); - - arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); - if (!arg_obj) { - ret = -ENOENT; - goto out; - } + arg_obj = drm_mode_object_find(dev, file_priv, arg->obj_id, arg->obj_type); + if (!arg_obj) + return -ENOENT; if (!arg_obj->properties) goto out_unref; @@ -408,28 +518,12 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, if (!property) goto out_unref; - if (!drm_property_change_valid_get(property, arg->value, &ref)) - goto out_unref; - - switch (arg_obj->type) { - case DRM_MODE_OBJECT_CONNECTOR: - ret = drm_mode_connector_set_obj_prop(arg_obj, property, - arg->value); - break; - case DRM_MODE_OBJECT_CRTC: - ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value); - break; - case DRM_MODE_OBJECT_PLANE: - ret = drm_mode_plane_set_obj_prop(obj_to_plane(arg_obj), - property, arg->value); - break; - } - - drm_property_change_valid_put(property, ref); + if (drm_drv_uses_atomic_modeset(property->dev)) + ret = set_property_atomic(arg_obj, property, arg->value); + else + ret = set_property_legacy(arg_obj, property, arg->value); out_unref: drm_mode_object_put(arg_obj); -out: - drm_modeset_unlock_all(dev); return ret; } |