1 /* 2 * Copyright (c) 2016 Intel Corporation 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that copyright 7 * notice and this permission notice appear in supporting documentation, and 8 * that the name of the copyright holders not be used in advertising or 9 * publicity pertaining to distribution of the software without specific, 10 * written prior permission. The copyright holders make no representations 11 * about the suitability of this software for any purpose. It is provided "as 12 * is" without express or implied warranty. 13 * 14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 * OF THIS SOFTWARE. 21 */ 22 23 #include <linux/export.h> 24 #include <drm/drmP.h> 25 #include <drm/drm_mode_object.h> 26 #include <drm/drm_atomic.h> 27 28 #include "drm_crtc_internal.h" 29 30 /* 31 * Internal function to assign a slot in the object idr and optionally 32 * register the object into the idr. 33 */ 34 int __drm_mode_object_add(struct drm_device *dev, struct drm_mode_object *obj, 35 uint32_t obj_type, bool register_obj, 36 void (*obj_free_cb)(struct kref *kref)) 37 { 38 int ret; 39 40 mutex_lock(&dev->mode_config.idr_mutex); 41 ret = idr_alloc(&dev->mode_config.object_idr, register_obj ? obj : NULL, 42 1, 0, GFP_KERNEL); 43 if (ret >= 0) { 44 /* 45 * Set up the object linking under the protection of the idr 46 * lock so that other users can't see inconsistent state. 47 */ 48 obj->id = ret; 49 obj->type = obj_type; 50 if (obj_free_cb) { 51 obj->free_cb = obj_free_cb; 52 kref_init(&obj->refcount); 53 } 54 } 55 mutex_unlock(&dev->mode_config.idr_mutex); 56 57 return ret < 0 ? ret : 0; 58 } 59 60 /** 61 * drm_mode_object_add - allocate a new modeset identifier 62 * @dev: DRM device 63 * @obj: object pointer, used to generate unique ID 64 * @obj_type: object type 65 * 66 * Create a unique identifier based on @ptr in @dev's identifier space. Used 67 * for tracking modes, CRTCs and connectors. 68 * 69 * Returns: 70 * Zero on success, error code on failure. 71 */ 72 int drm_mode_object_add(struct drm_device *dev, 73 struct drm_mode_object *obj, uint32_t obj_type) 74 { 75 return __drm_mode_object_add(dev, obj, obj_type, true, NULL); 76 } 77 78 void drm_mode_object_register(struct drm_device *dev, 79 struct drm_mode_object *obj) 80 { 81 mutex_lock(&dev->mode_config.idr_mutex); 82 idr_replace(&dev->mode_config.object_idr, obj, obj->id); 83 mutex_unlock(&dev->mode_config.idr_mutex); 84 } 85 86 /** 87 * drm_mode_object_unregister - free a modeset identifer 88 * @dev: DRM device 89 * @object: object to free 90 * 91 * Free @id from @dev's unique identifier pool. 92 * This function can be called multiple times, and guards against 93 * multiple removals. 94 * These modeset identifiers are _not_ reference counted. Hence don't use this 95 * for reference counted modeset objects like framebuffers. 96 */ 97 void drm_mode_object_unregister(struct drm_device *dev, 98 struct drm_mode_object *object) 99 { 100 mutex_lock(&dev->mode_config.idr_mutex); 101 if (object->id) { 102 idr_remove(&dev->mode_config.object_idr, object->id); 103 object->id = 0; 104 } 105 mutex_unlock(&dev->mode_config.idr_mutex); 106 } 107 108 /** 109 * drm_lease_required - check types which must be leased to be used 110 * @type: type of object 111 * 112 * Returns whether the provided type of drm_mode_object must 113 * be owned or leased to be used by a process. 114 */ 115 bool drm_mode_object_lease_required(uint32_t type) 116 { 117 switch(type) { 118 case DRM_MODE_OBJECT_CRTC: 119 case DRM_MODE_OBJECT_CONNECTOR: 120 case DRM_MODE_OBJECT_PLANE: 121 return true; 122 default: 123 return false; 124 } 125 } 126 127 struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev, 128 struct drm_file *file_priv, 129 uint32_t id, uint32_t type) 130 { 131 struct drm_mode_object *obj = NULL; 132 133 mutex_lock(&dev->mode_config.idr_mutex); 134 obj = idr_find(&dev->mode_config.object_idr, id); 135 if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type) 136 obj = NULL; 137 if (obj && obj->id != id) 138 obj = NULL; 139 140 if (obj && drm_mode_object_lease_required(obj->type) && 141 !_drm_lease_held(file_priv, obj->id)) 142 obj = NULL; 143 144 if (obj && obj->free_cb) { 145 if (!kref_get_unless_zero(&obj->refcount)) 146 obj = NULL; 147 } 148 mutex_unlock(&dev->mode_config.idr_mutex); 149 150 return obj; 151 } 152 153 /** 154 * drm_mode_object_find - look up a drm object with static lifetime 155 * @dev: drm device 156 * @file_priv: drm file 157 * @id: id of the mode object 158 * @type: type of the mode object 159 * 160 * This function is used to look up a modeset object. It will acquire a 161 * reference for reference counted objects. This reference must be dropped again 162 * by callind drm_mode_object_put(). 163 */ 164 struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, 165 struct drm_file *file_priv, 166 uint32_t id, uint32_t type) 167 { 168 struct drm_mode_object *obj = NULL; 169 170 obj = __drm_mode_object_find(dev, file_priv, id, type); 171 return obj; 172 } 173 EXPORT_SYMBOL(drm_mode_object_find); 174 175 /** 176 * drm_mode_object_put - release a mode object reference 177 * @obj: DRM mode object 178 * 179 * This function decrements the object's refcount if it is a refcounted modeset 180 * object. It is a no-op on any other object. This is used to drop references 181 * acquired with drm_mode_object_get(). 182 */ 183 void drm_mode_object_put(struct drm_mode_object *obj) 184 { 185 if (obj->free_cb) { 186 DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, kref_read(&obj->refcount)); 187 kref_put(&obj->refcount, obj->free_cb); 188 } 189 } 190 EXPORT_SYMBOL(drm_mode_object_put); 191 192 /** 193 * drm_mode_object_get - acquire a mode object reference 194 * @obj: DRM mode object 195 * 196 * This function increments the object's refcount if it is a refcounted modeset 197 * object. It is a no-op on any other object. References should be dropped again 198 * by calling drm_mode_object_put(). 199 */ 200 void drm_mode_object_get(struct drm_mode_object *obj) 201 { 202 if (obj->free_cb) { 203 DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, kref_read(&obj->refcount)); 204 kref_get(&obj->refcount); 205 } 206 } 207 EXPORT_SYMBOL(drm_mode_object_get); 208 209 /** 210 * drm_object_attach_property - attach a property to a modeset object 211 * @obj: drm modeset object 212 * @property: property to attach 213 * @init_val: initial value of the property 214 * 215 * This attaches the given property to the modeset object with the given initial 216 * value. Currently this function cannot fail since the properties are stored in 217 * a statically sized array. 218 */ 219 void drm_object_attach_property(struct drm_mode_object *obj, 220 struct drm_property *property, 221 uint64_t init_val) 222 { 223 int count = obj->properties->count; 224 225 if (count == DRM_OBJECT_MAX_PROPERTY) { 226 WARN(1, "Failed to attach object property (type: 0x%x). Please " 227 "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time " 228 "you see this message on the same object type.\n", 229 obj->type); 230 return; 231 } 232 233 obj->properties->properties[count] = property; 234 obj->properties->values[count] = init_val; 235 obj->properties->count++; 236 } 237 EXPORT_SYMBOL(drm_object_attach_property); 238 239 /** 240 * drm_object_property_set_value - set the value of a property 241 * @obj: drm mode object to set property value for 242 * @property: property to set 243 * @val: value the property should be set to 244 * 245 * This function sets a given property on a given object. This function only 246 * changes the software state of the property, it does not call into the 247 * driver's ->set_property callback. 248 * 249 * Note that atomic drivers should not have any need to call this, the core will 250 * ensure consistency of values reported back to userspace through the 251 * appropriate ->atomic_get_property callback. Only legacy drivers should call 252 * this function to update the tracked value (after clamping and other 253 * restrictions have been applied). 254 * 255 * Returns: 256 * Zero on success, error code on failure. 257 */ 258 int drm_object_property_set_value(struct drm_mode_object *obj, 259 struct drm_property *property, uint64_t val) 260 { 261 int i; 262 263 WARN_ON(drm_drv_uses_atomic_modeset(property->dev) && 264 !(property->flags & DRM_MODE_PROP_IMMUTABLE)); 265 266 for (i = 0; i < obj->properties->count; i++) { 267 if (obj->properties->properties[i] == property) { 268 obj->properties->values[i] = val; 269 return 0; 270 } 271 } 272 273 return -EINVAL; 274 } 275 EXPORT_SYMBOL(drm_object_property_set_value); 276 277 static int __drm_object_property_get_value(struct drm_mode_object *obj, 278 struct drm_property *property, 279 uint64_t *val) 280 { 281 int i; 282 283 /* read-only properties bypass atomic mechanism and still store 284 * their value in obj->properties->values[].. mostly to avoid 285 * having to deal w/ EDID and similar props in atomic paths: 286 */ 287 if (drm_drv_uses_atomic_modeset(property->dev) && 288 !(property->flags & DRM_MODE_PROP_IMMUTABLE)) 289 return drm_atomic_get_property(obj, property, val); 290 291 for (i = 0; i < obj->properties->count; i++) { 292 if (obj->properties->properties[i] == property) { 293 *val = obj->properties->values[i]; 294 return 0; 295 } 296 297 } 298 299 return -EINVAL; 300 } 301 302 /** 303 * drm_object_property_get_value - retrieve the value of a property 304 * @obj: drm mode object to get property value from 305 * @property: property to retrieve 306 * @val: storage for the property value 307 * 308 * This function retrieves the softare state of the given property for the given 309 * property. Since there is no driver callback to retrieve the current property 310 * value this might be out of sync with the hardware, depending upon the driver 311 * and property. 312 * 313 * Atomic drivers should never call this function directly, the core will read 314 * out property values through the various ->atomic_get_property callbacks. 315 * 316 * Returns: 317 * Zero on success, error code on failure. 318 */ 319 int drm_object_property_get_value(struct drm_mode_object *obj, 320 struct drm_property *property, uint64_t *val) 321 { 322 WARN_ON(drm_drv_uses_atomic_modeset(property->dev)); 323 324 return __drm_object_property_get_value(obj, property, val); 325 } 326 EXPORT_SYMBOL(drm_object_property_get_value); 327 328 /* helper for getconnector and getproperties ioctls */ 329 int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic, 330 uint32_t __user *prop_ptr, 331 uint64_t __user *prop_values, 332 uint32_t *arg_count_props) 333 { 334 int i, ret, count; 335 336 for (i = 0, count = 0; i < obj->properties->count; i++) { 337 struct drm_property *prop = obj->properties->properties[i]; 338 uint64_t val; 339 340 if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic) 341 continue; 342 343 if (*arg_count_props > count) { 344 ret = __drm_object_property_get_value(obj, prop, &val); 345 if (ret) 346 return ret; 347 348 if (put_user(prop->base.id, prop_ptr + count)) 349 return -EFAULT; 350 351 if (put_user(val, prop_values + count)) 352 return -EFAULT; 353 } 354 355 count++; 356 } 357 *arg_count_props = count; 358 359 return 0; 360 } 361 362 /** 363 * drm_mode_obj_get_properties_ioctl - get the current value of a object's property 364 * @dev: DRM device 365 * @data: ioctl data 366 * @file_priv: DRM file info 367 * 368 * This function retrieves the current value for an object's property. Compared 369 * to the connector specific ioctl this one is extended to also work on crtc and 370 * plane objects. 371 * 372 * Called by the user via ioctl. 373 * 374 * Returns: 375 * Zero on success, negative errno on failure. 376 */ 377 int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, 378 struct drm_file *file_priv) 379 { 380 struct drm_mode_obj_get_properties *arg = data; 381 struct drm_mode_object *obj; 382 int ret = 0; 383 384 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 385 return -EOPNOTSUPP; 386 387 drm_modeset_lock_all(dev); 388 389 obj = drm_mode_object_find(dev, file_priv, arg->obj_id, arg->obj_type); 390 if (!obj) { 391 ret = -ENOENT; 392 goto out; 393 } 394 if (!obj->properties) { 395 ret = -EINVAL; 396 goto out_unref; 397 } 398 399 ret = drm_mode_object_get_properties(obj, file_priv->atomic, 400 (uint32_t __user *)(unsigned long)(arg->props_ptr), 401 (uint64_t __user *)(unsigned long)(arg->prop_values_ptr), 402 &arg->count_props); 403 404 out_unref: 405 drm_mode_object_put(obj); 406 out: 407 drm_modeset_unlock_all(dev); 408 return ret; 409 } 410 411 struct drm_property *drm_mode_obj_find_prop_id(struct drm_mode_object *obj, 412 uint32_t prop_id) 413 { 414 int i; 415 416 for (i = 0; i < obj->properties->count; i++) 417 if (obj->properties->properties[i]->base.id == prop_id) 418 return obj->properties->properties[i]; 419 420 return NULL; 421 } 422 423 static int set_property_legacy(struct drm_mode_object *obj, 424 struct drm_property *prop, 425 uint64_t prop_value) 426 { 427 struct drm_device *dev = prop->dev; 428 struct drm_mode_object *ref; 429 int ret = -EINVAL; 430 431 if (!drm_property_change_valid_get(prop, prop_value, &ref)) 432 return -EINVAL; 433 434 drm_modeset_lock_all(dev); 435 switch (obj->type) { 436 case DRM_MODE_OBJECT_CONNECTOR: 437 ret = drm_connector_set_obj_prop(obj, prop, prop_value); 438 break; 439 case DRM_MODE_OBJECT_CRTC: 440 ret = drm_mode_crtc_set_obj_prop(obj, prop, prop_value); 441 break; 442 case DRM_MODE_OBJECT_PLANE: 443 ret = drm_mode_plane_set_obj_prop(obj_to_plane(obj), 444 prop, prop_value); 445 break; 446 } 447 drm_property_change_valid_put(prop, ref); 448 drm_modeset_unlock_all(dev); 449 450 return ret; 451 } 452 453 static int set_property_atomic(struct drm_mode_object *obj, 454 struct drm_property *prop, 455 uint64_t prop_value) 456 { 457 struct drm_device *dev = prop->dev; 458 struct drm_atomic_state *state; 459 struct drm_modeset_acquire_ctx ctx; 460 int ret; 461 462 state = drm_atomic_state_alloc(dev); 463 if (!state) 464 return -ENOMEM; 465 466 drm_modeset_acquire_init(&ctx, 0); 467 state->acquire_ctx = &ctx; 468 469 retry: 470 if (prop == state->dev->mode_config.dpms_property) { 471 if (obj->type != DRM_MODE_OBJECT_CONNECTOR) { 472 ret = -EINVAL; 473 goto out; 474 } 475 476 ret = drm_atomic_connector_commit_dpms(state, 477 obj_to_connector(obj), 478 prop_value); 479 } else { 480 ret = drm_atomic_set_property(state, obj, prop, prop_value); 481 if (ret) 482 goto out; 483 ret = drm_atomic_commit(state); 484 } 485 out: 486 if (ret == -EDEADLK) { 487 drm_atomic_state_clear(state); 488 drm_modeset_backoff(&ctx); 489 goto retry; 490 } 491 492 drm_atomic_state_put(state); 493 494 drm_modeset_drop_locks(&ctx); 495 drm_modeset_acquire_fini(&ctx); 496 497 return ret; 498 } 499 500 int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, 501 struct drm_file *file_priv) 502 { 503 struct drm_mode_obj_set_property *arg = data; 504 struct drm_mode_object *arg_obj; 505 struct drm_property *property; 506 int ret = -EINVAL; 507 508 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 509 return -EOPNOTSUPP; 510 511 arg_obj = drm_mode_object_find(dev, file_priv, arg->obj_id, arg->obj_type); 512 if (!arg_obj) 513 return -ENOENT; 514 515 if (!arg_obj->properties) 516 goto out_unref; 517 518 property = drm_mode_obj_find_prop_id(arg_obj, arg->prop_id); 519 if (!property) 520 goto out_unref; 521 522 if (drm_drv_uses_atomic_modeset(property->dev)) 523 ret = set_property_atomic(arg_obj, property, arg->value); 524 else 525 ret = set_property_legacy(arg_obj, property, arg->value); 526 527 out_unref: 528 drm_mode_object_put(arg_obj); 529 return ret; 530 } 531