0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023 #include <linux/export.h>
0024 #include <linux/uaccess.h>
0025
0026 #include <drm/drm_atomic.h>
0027 #include <drm/drm_drv.h>
0028 #include <drm/drm_device.h>
0029 #include <drm/drm_file.h>
0030 #include <drm/drm_mode_object.h>
0031 #include <drm/drm_print.h>
0032
0033 #include "drm_crtc_internal.h"
0034
0035
0036
0037
0038
0039 int __drm_mode_object_add(struct drm_device *dev, struct drm_mode_object *obj,
0040 uint32_t obj_type, bool register_obj,
0041 void (*obj_free_cb)(struct kref *kref))
0042 {
0043 int ret;
0044
0045 WARN_ON(!dev->driver->load && dev->registered && !obj_free_cb);
0046
0047 mutex_lock(&dev->mode_config.idr_mutex);
0048 ret = idr_alloc(&dev->mode_config.object_idr, register_obj ? obj : NULL,
0049 1, 0, GFP_KERNEL);
0050 if (ret >= 0) {
0051
0052
0053
0054
0055 obj->id = ret;
0056 obj->type = obj_type;
0057 if (obj_free_cb) {
0058 obj->free_cb = obj_free_cb;
0059 kref_init(&obj->refcount);
0060 }
0061 }
0062 mutex_unlock(&dev->mode_config.idr_mutex);
0063
0064 return ret < 0 ? ret : 0;
0065 }
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079 int drm_mode_object_add(struct drm_device *dev,
0080 struct drm_mode_object *obj, uint32_t obj_type)
0081 {
0082 return __drm_mode_object_add(dev, obj, obj_type, true, NULL);
0083 }
0084
0085 void drm_mode_object_register(struct drm_device *dev,
0086 struct drm_mode_object *obj)
0087 {
0088 mutex_lock(&dev->mode_config.idr_mutex);
0089 idr_replace(&dev->mode_config.object_idr, obj, obj->id);
0090 mutex_unlock(&dev->mode_config.idr_mutex);
0091 }
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104 void drm_mode_object_unregister(struct drm_device *dev,
0105 struct drm_mode_object *object)
0106 {
0107 WARN_ON(!dev->driver->load && dev->registered && !object->free_cb);
0108
0109 mutex_lock(&dev->mode_config.idr_mutex);
0110 if (object->id) {
0111 idr_remove(&dev->mode_config.object_idr, object->id);
0112 object->id = 0;
0113 }
0114 mutex_unlock(&dev->mode_config.idr_mutex);
0115 }
0116
0117
0118
0119
0120
0121
0122
0123
0124 bool drm_mode_object_lease_required(uint32_t type)
0125 {
0126 switch(type) {
0127 case DRM_MODE_OBJECT_CRTC:
0128 case DRM_MODE_OBJECT_CONNECTOR:
0129 case DRM_MODE_OBJECT_PLANE:
0130 return true;
0131 default:
0132 return false;
0133 }
0134 }
0135
0136 struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev,
0137 struct drm_file *file_priv,
0138 uint32_t id, uint32_t type)
0139 {
0140 struct drm_mode_object *obj = NULL;
0141
0142 mutex_lock(&dev->mode_config.idr_mutex);
0143 obj = idr_find(&dev->mode_config.object_idr, id);
0144 if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type)
0145 obj = NULL;
0146 if (obj && obj->id != id)
0147 obj = NULL;
0148
0149 if (obj && drm_mode_object_lease_required(obj->type) &&
0150 !_drm_lease_held(file_priv, obj->id))
0151 obj = NULL;
0152
0153 if (obj && obj->free_cb) {
0154 if (!kref_get_unless_zero(&obj->refcount))
0155 obj = NULL;
0156 }
0157 mutex_unlock(&dev->mode_config.idr_mutex);
0158
0159 return obj;
0160 }
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173 struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
0174 struct drm_file *file_priv,
0175 uint32_t id, uint32_t type)
0176 {
0177 struct drm_mode_object *obj = NULL;
0178
0179 obj = __drm_mode_object_find(dev, file_priv, id, type);
0180 return obj;
0181 }
0182 EXPORT_SYMBOL(drm_mode_object_find);
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192 void drm_mode_object_put(struct drm_mode_object *obj)
0193 {
0194 if (obj->free_cb) {
0195 DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, kref_read(&obj->refcount));
0196 kref_put(&obj->refcount, obj->free_cb);
0197 }
0198 }
0199 EXPORT_SYMBOL(drm_mode_object_put);
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209 void drm_mode_object_get(struct drm_mode_object *obj)
0210 {
0211 if (obj->free_cb) {
0212 DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, kref_read(&obj->refcount));
0213 kref_get(&obj->refcount);
0214 }
0215 }
0216 EXPORT_SYMBOL(drm_mode_object_get);
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231 void drm_object_attach_property(struct drm_mode_object *obj,
0232 struct drm_property *property,
0233 uint64_t init_val)
0234 {
0235 int count = obj->properties->count;
0236 struct drm_device *dev = property->dev;
0237
0238
0239 if (obj->type == DRM_MODE_OBJECT_CONNECTOR) {
0240 struct drm_connector *connector = obj_to_connector(obj);
0241
0242 WARN_ON(!dev->driver->load &&
0243 connector->registration_state == DRM_CONNECTOR_REGISTERED);
0244 } else {
0245 WARN_ON(!dev->driver->load && dev->registered);
0246 }
0247
0248 if (count == DRM_OBJECT_MAX_PROPERTY) {
0249 WARN(1, "Failed to attach object property (type: 0x%x). Please "
0250 "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time "
0251 "you see this message on the same object type.\n",
0252 obj->type);
0253 return;
0254 }
0255
0256 obj->properties->properties[count] = property;
0257 obj->properties->values[count] = init_val;
0258 obj->properties->count++;
0259 }
0260 EXPORT_SYMBOL(drm_object_attach_property);
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281 int drm_object_property_set_value(struct drm_mode_object *obj,
0282 struct drm_property *property, uint64_t val)
0283 {
0284 int i;
0285
0286 WARN_ON(drm_drv_uses_atomic_modeset(property->dev) &&
0287 !(property->flags & DRM_MODE_PROP_IMMUTABLE));
0288
0289 for (i = 0; i < obj->properties->count; i++) {
0290 if (obj->properties->properties[i] == property) {
0291 obj->properties->values[i] = val;
0292 return 0;
0293 }
0294 }
0295
0296 return -EINVAL;
0297 }
0298 EXPORT_SYMBOL(drm_object_property_set_value);
0299
0300 static int __drm_object_property_get_prop_value(struct drm_mode_object *obj,
0301 struct drm_property *property,
0302 uint64_t *val)
0303 {
0304 int i;
0305
0306 for (i = 0; i < obj->properties->count; i++) {
0307 if (obj->properties->properties[i] == property) {
0308 *val = obj->properties->values[i];
0309 return 0;
0310 }
0311 }
0312
0313 return -EINVAL;
0314 }
0315
0316 static int __drm_object_property_get_value(struct drm_mode_object *obj,
0317 struct drm_property *property,
0318 uint64_t *val)
0319 {
0320
0321
0322
0323
0324
0325 if (drm_drv_uses_atomic_modeset(property->dev) &&
0326 !(property->flags & DRM_MODE_PROP_IMMUTABLE))
0327 return drm_atomic_get_property(obj, property, val);
0328
0329 return __drm_object_property_get_prop_value(obj, property, val);
0330 }
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349 int drm_object_property_get_value(struct drm_mode_object *obj,
0350 struct drm_property *property, uint64_t *val)
0351 {
0352 WARN_ON(drm_drv_uses_atomic_modeset(property->dev));
0353
0354 return __drm_object_property_get_value(obj, property, val);
0355 }
0356 EXPORT_SYMBOL(drm_object_property_get_value);
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372
0373
0374 int drm_object_property_get_default_value(struct drm_mode_object *obj,
0375 struct drm_property *property,
0376 uint64_t *val)
0377 {
0378 WARN_ON(!drm_drv_uses_atomic_modeset(property->dev));
0379
0380 return __drm_object_property_get_prop_value(obj, property, val);
0381 }
0382 EXPORT_SYMBOL(drm_object_property_get_default_value);
0383
0384
0385 int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic,
0386 uint32_t __user *prop_ptr,
0387 uint64_t __user *prop_values,
0388 uint32_t *arg_count_props)
0389 {
0390 int i, ret, count;
0391
0392 for (i = 0, count = 0; i < obj->properties->count; i++) {
0393 struct drm_property *prop = obj->properties->properties[i];
0394 uint64_t val;
0395
0396 if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic)
0397 continue;
0398
0399 if (*arg_count_props > count) {
0400 ret = __drm_object_property_get_value(obj, prop, &val);
0401 if (ret)
0402 return ret;
0403
0404 if (put_user(prop->base.id, prop_ptr + count))
0405 return -EFAULT;
0406
0407 if (put_user(val, prop_values + count))
0408 return -EFAULT;
0409 }
0410
0411 count++;
0412 }
0413 *arg_count_props = count;
0414
0415 return 0;
0416 }
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432
0433 int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
0434 struct drm_file *file_priv)
0435 {
0436 struct drm_mode_obj_get_properties *arg = data;
0437 struct drm_mode_object *obj;
0438 struct drm_modeset_acquire_ctx ctx;
0439 int ret = 0;
0440
0441 if (!drm_core_check_feature(dev, DRIVER_MODESET))
0442 return -EOPNOTSUPP;
0443
0444 DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret);
0445
0446 obj = drm_mode_object_find(dev, file_priv, arg->obj_id, arg->obj_type);
0447 if (!obj) {
0448 ret = -ENOENT;
0449 goto out;
0450 }
0451 if (!obj->properties) {
0452 ret = -EINVAL;
0453 goto out_unref;
0454 }
0455
0456 ret = drm_mode_object_get_properties(obj, file_priv->atomic,
0457 (uint32_t __user *)(unsigned long)(arg->props_ptr),
0458 (uint64_t __user *)(unsigned long)(arg->prop_values_ptr),
0459 &arg->count_props);
0460
0461 out_unref:
0462 drm_mode_object_put(obj);
0463 out:
0464 DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
0465 return ret;
0466 }
0467
0468 struct drm_property *drm_mode_obj_find_prop_id(struct drm_mode_object *obj,
0469 uint32_t prop_id)
0470 {
0471 int i;
0472
0473 for (i = 0; i < obj->properties->count; i++)
0474 if (obj->properties->properties[i]->base.id == prop_id)
0475 return obj->properties->properties[i];
0476
0477 return NULL;
0478 }
0479
0480 static int set_property_legacy(struct drm_mode_object *obj,
0481 struct drm_property *prop,
0482 uint64_t prop_value)
0483 {
0484 struct drm_device *dev = prop->dev;
0485 struct drm_mode_object *ref;
0486 struct drm_modeset_acquire_ctx ctx;
0487 int ret = -EINVAL;
0488
0489 if (!drm_property_change_valid_get(prop, prop_value, &ref))
0490 return -EINVAL;
0491
0492 DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret);
0493 switch (obj->type) {
0494 case DRM_MODE_OBJECT_CONNECTOR:
0495 ret = drm_connector_set_obj_prop(obj, prop, prop_value);
0496 break;
0497 case DRM_MODE_OBJECT_CRTC:
0498 ret = drm_mode_crtc_set_obj_prop(obj, prop, prop_value);
0499 break;
0500 case DRM_MODE_OBJECT_PLANE:
0501 ret = drm_mode_plane_set_obj_prop(obj_to_plane(obj),
0502 prop, prop_value);
0503 break;
0504 }
0505 drm_property_change_valid_put(prop, ref);
0506 DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
0507
0508 return ret;
0509 }
0510
0511 static int set_property_atomic(struct drm_mode_object *obj,
0512 struct drm_file *file_priv,
0513 struct drm_property *prop,
0514 uint64_t prop_value)
0515 {
0516 struct drm_device *dev = prop->dev;
0517 struct drm_atomic_state *state;
0518 struct drm_modeset_acquire_ctx ctx;
0519 int ret;
0520
0521 state = drm_atomic_state_alloc(dev);
0522 if (!state)
0523 return -ENOMEM;
0524
0525 drm_modeset_acquire_init(&ctx, 0);
0526 state->acquire_ctx = &ctx;
0527
0528 retry:
0529 if (prop == state->dev->mode_config.dpms_property) {
0530 if (obj->type != DRM_MODE_OBJECT_CONNECTOR) {
0531 ret = -EINVAL;
0532 goto out;
0533 }
0534
0535 ret = drm_atomic_connector_commit_dpms(state,
0536 obj_to_connector(obj),
0537 prop_value);
0538 } else {
0539 ret = drm_atomic_set_property(state, file_priv, obj, prop, prop_value);
0540 if (ret)
0541 goto out;
0542 ret = drm_atomic_commit(state);
0543 }
0544 out:
0545 if (ret == -EDEADLK) {
0546 drm_atomic_state_clear(state);
0547 drm_modeset_backoff(&ctx);
0548 goto retry;
0549 }
0550
0551 drm_atomic_state_put(state);
0552
0553 drm_modeset_drop_locks(&ctx);
0554 drm_modeset_acquire_fini(&ctx);
0555
0556 return ret;
0557 }
0558
0559 int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
0560 struct drm_file *file_priv)
0561 {
0562 struct drm_mode_obj_set_property *arg = data;
0563 struct drm_mode_object *arg_obj;
0564 struct drm_property *property;
0565 int ret = -EINVAL;
0566
0567 if (!drm_core_check_feature(dev, DRIVER_MODESET))
0568 return -EOPNOTSUPP;
0569
0570 arg_obj = drm_mode_object_find(dev, file_priv, arg->obj_id, arg->obj_type);
0571 if (!arg_obj)
0572 return -ENOENT;
0573
0574 if (!arg_obj->properties)
0575 goto out_unref;
0576
0577 property = drm_mode_obj_find_prop_id(arg_obj, arg->prop_id);
0578 if (!property)
0579 goto out_unref;
0580
0581 if (drm_drv_uses_atomic_modeset(property->dev))
0582 ret = set_property_atomic(arg_obj, file_priv, property, arg->value);
0583 else
0584 ret = set_property_legacy(arg_obj, property, arg->value);
0585
0586 out_unref:
0587 drm_mode_object_put(arg_obj);
0588 return ret;
0589 }