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