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_get_reg(struct drm_device *dev, 35 struct drm_mode_object *obj, 36 uint32_t obj_type, 37 bool register_obj, 38 void (*obj_free_cb)(struct kref *kref)) 39 { 40 int ret; 41 42 mutex_lock(&dev->mode_config.idr_mutex); 43 ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL, 1, 0, GFP_KERNEL); 44 if (ret >= 0) { 45 /* 46 * Set up the object linking under the protection of the idr 47 * lock so that other users can't see inconsistent state. 48 */ 49 obj->id = ret; 50 obj->type = obj_type; 51 if (obj_free_cb) { 52 obj->free_cb = obj_free_cb; 53 kref_init(&obj->refcount); 54 } 55 } 56 mutex_unlock(&dev->mode_config.idr_mutex); 57 58 return ret < 0 ? ret : 0; 59 } 60 61 /** 62 * drm_mode_object_get - allocate a new modeset identifier 63 * @dev: DRM device 64 * @obj: object pointer, used to generate unique ID 65 * @obj_type: object type 66 * 67 * Create a unique identifier based on @ptr in @dev's identifier space. Used 68 * for tracking modes, CRTCs and connectors. Note that despite the _get postfix 69 * modeset identifiers are _not_ reference counted. Hence don't use this for 70 * reference counted modeset objects like framebuffers. 71 * 72 * Returns: 73 * Zero on success, error code on failure. 74 */ 75 int drm_mode_object_get(struct drm_device *dev, 76 struct drm_mode_object *obj, uint32_t obj_type) 77 { 78 return drm_mode_object_get_reg(dev, obj, obj_type, true, NULL); 79 } 80 81 void drm_mode_object_register(struct drm_device *dev, 82 struct drm_mode_object *obj) 83 { 84 mutex_lock(&dev->mode_config.idr_mutex); 85 idr_replace(&dev->mode_config.crtc_idr, obj, obj->id); 86 mutex_unlock(&dev->mode_config.idr_mutex); 87 } 88 89 /** 90 * drm_mode_object_unregister - free a modeset identifer 91 * @dev: DRM device 92 * @object: object to free 93 * 94 * Free @id from @dev's unique identifier pool. 95 * This function can be called multiple times, and guards against 96 * multiple removals. 97 * These modeset identifiers are _not_ reference counted. Hence don't use this 98 * for reference counted modeset objects like framebuffers. 99 */ 100 void drm_mode_object_unregister(struct drm_device *dev, 101 struct drm_mode_object *object) 102 { 103 mutex_lock(&dev->mode_config.idr_mutex); 104 if (object->id) { 105 idr_remove(&dev->mode_config.crtc_idr, object->id); 106 object->id = 0; 107 } 108 mutex_unlock(&dev->mode_config.idr_mutex); 109 } 110 111 struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev, 112 uint32_t id, uint32_t type) 113 { 114 struct drm_mode_object *obj = NULL; 115 116 mutex_lock(&dev->mode_config.idr_mutex); 117 obj = idr_find(&dev->mode_config.crtc_idr, id); 118 if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type) 119 obj = NULL; 120 if (obj && obj->id != id) 121 obj = NULL; 122 123 if (obj && obj->free_cb) { 124 if (!kref_get_unless_zero(&obj->refcount)) 125 obj = NULL; 126 } 127 mutex_unlock(&dev->mode_config.idr_mutex); 128 129 return obj; 130 } 131 132 /** 133 * drm_mode_object_find - look up a drm object with static lifetime 134 * @dev: drm device 135 * @id: id of the mode object 136 * @type: type of the mode object 137 * 138 * This function is used to look up a modeset object. It will acquire a 139 * reference for reference counted objects. This reference must be dropped again 140 * by callind drm_mode_object_unreference(). 141 */ 142 struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, 143 uint32_t id, uint32_t type) 144 { 145 struct drm_mode_object *obj = NULL; 146 147 obj = __drm_mode_object_find(dev, id, type); 148 return obj; 149 } 150 EXPORT_SYMBOL(drm_mode_object_find); 151 152 /** 153 * drm_mode_object_unreference - decr the object refcnt 154 * @obj: mode_object 155 * 156 * This function decrements the object's refcount if it is a refcounted modeset 157 * object. It is a no-op on any other object. This is used to drop references 158 * acquired with drm_mode_object_reference(). 159 */ 160 void drm_mode_object_unreference(struct drm_mode_object *obj) 161 { 162 if (obj->free_cb) { 163 DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, kref_read(&obj->refcount)); 164 kref_put(&obj->refcount, obj->free_cb); 165 } 166 } 167 EXPORT_SYMBOL(drm_mode_object_unreference); 168 169 /** 170 * drm_mode_object_reference - incr the object refcnt 171 * @obj: mode_object 172 * 173 * This function increments the object's refcount if it is a refcounted modeset 174 * object. It is a no-op on any other object. References should be dropped again 175 * by calling drm_mode_object_unreference(). 176 */ 177 void drm_mode_object_reference(struct drm_mode_object *obj) 178 { 179 if (obj->free_cb) { 180 DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, kref_read(&obj->refcount)); 181 kref_get(&obj->refcount); 182 } 183 } 184 EXPORT_SYMBOL(drm_mode_object_reference); 185 186 /** 187 * drm_object_attach_property - attach a property to a modeset object 188 * @obj: drm modeset object 189 * @property: property to attach 190 * @init_val: initial value of the property 191 * 192 * This attaches the given property to the modeset object with the given initial 193 * value. Currently this function cannot fail since the properties are stored in 194 * a statically sized array. 195 */ 196 void drm_object_attach_property(struct drm_mode_object *obj, 197 struct drm_property *property, 198 uint64_t init_val) 199 { 200 int count = obj->properties->count; 201 202 if (count == DRM_OBJECT_MAX_PROPERTY) { 203 WARN(1, "Failed to attach object property (type: 0x%x). Please " 204 "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time " 205 "you see this message on the same object type.\n", 206 obj->type); 207 return; 208 } 209 210 obj->properties->properties[count] = property; 211 obj->properties->values[count] = init_val; 212 obj->properties->count++; 213 } 214 EXPORT_SYMBOL(drm_object_attach_property); 215 216 /** 217 * drm_object_property_set_value - set the value of a property 218 * @obj: drm mode object to set property value for 219 * @property: property to set 220 * @val: value the property should be set to 221 * 222 * This function sets a given property on a given object. This function only 223 * changes the software state of the property, it does not call into the 224 * driver's ->set_property callback. 225 * 226 * Note that atomic drivers should not have any need to call this, the core will 227 * ensure consistency of values reported back to userspace through the 228 * appropriate ->atomic_get_property callback. Only legacy drivers should call 229 * this function to update the tracked value (after clamping and other 230 * restrictions have been applied). 231 * 232 * Returns: 233 * Zero on success, error code on failure. 234 */ 235 int drm_object_property_set_value(struct drm_mode_object *obj, 236 struct drm_property *property, uint64_t val) 237 { 238 int i; 239 240 for (i = 0; i < obj->properties->count; i++) { 241 if (obj->properties->properties[i] == property) { 242 obj->properties->values[i] = val; 243 return 0; 244 } 245 } 246 247 return -EINVAL; 248 } 249 EXPORT_SYMBOL(drm_object_property_set_value); 250 251 /** 252 * drm_object_property_get_value - retrieve the value of a property 253 * @obj: drm mode object to get property value from 254 * @property: property to retrieve 255 * @val: storage for the property value 256 * 257 * This function retrieves the softare state of the given property for the given 258 * property. Since there is no driver callback to retrieve the current property 259 * value this might be out of sync with the hardware, depending upon the driver 260 * and property. 261 * 262 * Atomic drivers should never call this function directly, the core will read 263 * out property values through the various ->atomic_get_property callbacks. 264 * 265 * Returns: 266 * Zero on success, error code on failure. 267 */ 268 int drm_object_property_get_value(struct drm_mode_object *obj, 269 struct drm_property *property, uint64_t *val) 270 { 271 int i; 272 273 /* read-only properties bypass atomic mechanism and still store 274 * their value in obj->properties->values[].. mostly to avoid 275 * having to deal w/ EDID and similar props in atomic paths: 276 */ 277 if (drm_drv_uses_atomic_modeset(property->dev) && 278 !(property->flags & DRM_MODE_PROP_IMMUTABLE)) 279 return drm_atomic_get_property(obj, property, val); 280 281 for (i = 0; i < obj->properties->count; i++) { 282 if (obj->properties->properties[i] == property) { 283 *val = obj->properties->values[i]; 284 return 0; 285 } 286 287 } 288 289 return -EINVAL; 290 } 291 EXPORT_SYMBOL(drm_object_property_get_value); 292 293 /* helper for getconnector and getproperties ioctls */ 294 int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic, 295 uint32_t __user *prop_ptr, 296 uint64_t __user *prop_values, 297 uint32_t *arg_count_props) 298 { 299 int i, ret, count; 300 301 for (i = 0, count = 0; i < obj->properties->count; i++) { 302 struct drm_property *prop = obj->properties->properties[i]; 303 uint64_t val; 304 305 if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic) 306 continue; 307 308 if (*arg_count_props > count) { 309 ret = drm_object_property_get_value(obj, prop, &val); 310 if (ret) 311 return ret; 312 313 if (put_user(prop->base.id, prop_ptr + count)) 314 return -EFAULT; 315 316 if (put_user(val, prop_values + count)) 317 return -EFAULT; 318 } 319 320 count++; 321 } 322 *arg_count_props = count; 323 324 return 0; 325 } 326 327 /** 328 * drm_mode_obj_get_properties_ioctl - get the current value of a object's property 329 * @dev: DRM device 330 * @data: ioctl data 331 * @file_priv: DRM file info 332 * 333 * This function retrieves the current value for an object's property. Compared 334 * to the connector specific ioctl this one is extended to also work on crtc and 335 * plane objects. 336 * 337 * Called by the user via ioctl. 338 * 339 * Returns: 340 * Zero on success, negative errno on failure. 341 */ 342 int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, 343 struct drm_file *file_priv) 344 { 345 struct drm_mode_obj_get_properties *arg = data; 346 struct drm_mode_object *obj; 347 int ret = 0; 348 349 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 350 return -EINVAL; 351 352 drm_modeset_lock_all(dev); 353 354 obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); 355 if (!obj) { 356 ret = -ENOENT; 357 goto out; 358 } 359 if (!obj->properties) { 360 ret = -EINVAL; 361 goto out_unref; 362 } 363 364 ret = drm_mode_object_get_properties(obj, file_priv->atomic, 365 (uint32_t __user *)(unsigned long)(arg->props_ptr), 366 (uint64_t __user *)(unsigned long)(arg->prop_values_ptr), 367 &arg->count_props); 368 369 out_unref: 370 drm_mode_object_unreference(obj); 371 out: 372 drm_modeset_unlock_all(dev); 373 return ret; 374 } 375 376 struct drm_property *drm_mode_obj_find_prop_id(struct drm_mode_object *obj, 377 uint32_t prop_id) 378 { 379 int i; 380 381 for (i = 0; i < obj->properties->count; i++) 382 if (obj->properties->properties[i]->base.id == prop_id) 383 return obj->properties->properties[i]; 384 385 return NULL; 386 } 387 388 int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, 389 struct drm_file *file_priv) 390 { 391 struct drm_mode_obj_set_property *arg = data; 392 struct drm_mode_object *arg_obj; 393 struct drm_property *property; 394 int ret = -EINVAL; 395 struct drm_mode_object *ref; 396 397 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 398 return -EINVAL; 399 400 drm_modeset_lock_all(dev); 401 402 arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); 403 if (!arg_obj) { 404 ret = -ENOENT; 405 goto out; 406 } 407 408 if (!arg_obj->properties) 409 goto out_unref; 410 411 property = drm_mode_obj_find_prop_id(arg_obj, arg->prop_id); 412 if (!property) 413 goto out_unref; 414 415 if (!drm_property_change_valid_get(property, arg->value, &ref)) 416 goto out_unref; 417 418 switch (arg_obj->type) { 419 case DRM_MODE_OBJECT_CONNECTOR: 420 ret = drm_mode_connector_set_obj_prop(arg_obj, property, 421 arg->value); 422 break; 423 case DRM_MODE_OBJECT_CRTC: 424 ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value); 425 break; 426 case DRM_MODE_OBJECT_PLANE: 427 ret = drm_mode_plane_set_obj_prop(obj_to_plane(arg_obj), 428 property, arg->value); 429 break; 430 } 431 432 drm_property_change_valid_put(property, ref); 433 434 out_unref: 435 drm_mode_object_unreference(arg_obj); 436 out: 437 drm_modeset_unlock_all(dev); 438 return ret; 439 } 440